PowerShellに限らず、すべてのプログラミング/スクリプト言語を記述するうえで欠かせないのが「変数」だ。いまさらいうまでもなく変数とは、コード上で値を格納し、処理した結果を反映し、また、ほかへと引き渡す、すべての処理を行う上での基本となる仕組みのことだ。もっとも、(例えば)言語によっては変数を利用するうえで、あらかじめデータ型と名前を宣言する必要があるものもあるが、PowerShellにおいては、(多くのスクリプティング言語と同様)あらかじめ変数を宣言する必要はない。PowerShellでは、初めて値が代入されたタイミングで、必要に応じて変数が生成される(*)。
* 従って、厳密にはPowerShellの変数には「未初期化」という状態はない。PowerShellでは「値を持つ変数」か「存在しない変数」があるだけである。
さてその変数を利用するに当たって、まず理解しておく必要があるのが変数の命名規則だ。前編でも簡単に触れたように、PowerShellでは変数名を以下の規則に従って命名する必要がある。
厳密には${〜}のように、中カッコで変数名を囲めば任意の文字を利用できる。例えば以下のような変数名でもよい。
${Windows PowerShell + .NET Framework}
もちろん、変数名にはできるだけ内容が類推できる程度に簡潔な(必要以上に短く、ということではない)名前を付けることが重要であり、通常は上のような変数名を付けることは好ましくない。必要以上に長い変数名はタイプミスにもつながる一因であるので(しかも、PowerShellのように変数宣言が不要な言語ではタイプミスを検出するのが困難である)、通常は一般的な命名規則の中で変数名を決めるのが好ましいだろう。
PowerShellは、(やはり多くのスクリプティング言語と同様)データ型を区別しない言語である。ただし厳密にはデータ型を持たないわけではなく、与えられた実データに応じてPowerShellが自動的に適切なデータ型を与えてくれる。従って、次のようなコードもPowerShellでは正しい。
$x = 123
$x = "abc"
最初の文では変数$xには整数型が割り当てられ、次に文字列が代入されたところで$xは文字列型となる(文字列はクォート記号で囲む必要がある)。PowerShellがデータ型を持たないわけではない証拠に、変数のデータ型をGetTypeメソッドで確かめてみると、以下のようにSystem.Int32型が割り当てられていることが確認できる。
PS > $x = 123
PS > $x.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
このようなデータ型の動的な認識は、多くのケースで便利なものであるが、時として思わぬ不具合をもたらす場合もある。例えば次のようなケースだ。
PS > $x = "1"
PS > $y = 2
PS > $z = $x + $y
PS > Write-Output $z
12 ……文字列として変数$x、$yが連結処理される
PS > $x = 1
PS > $y = "2"
PS > $z = $x + $y
PS > Write-Output $z (*)
3 ……整数として変数$x、$yが加算処理される
* Write-Outputはコマンドレットの1つで、指定された式の値を標準出力に出力する。
PowerShellの「+」演算子には加算演算子と文字列連結演算子としての2つの役割がある。そのため「文字列+数値」ならば文字列連結演算子としての役割が優先され、「数値+文字列」ならば加算演算子としての役割が優先されるようである。規則を覚えてしまえばよいといえばそれまでであるが、当然、複雑なコードを記述していく中では誤解を招く一因ともなるもので、好ましくない。
そこでPowerShellでは明示的に変数の型を宣言する方法も提供している。具体的には、以下のリストのように変数名の先頭に角カッコで囲んだデータ型を明示する(*)。
PS > [System.Int32] $x = 10
PS > $x = 13.5
PS > Write-Output $x
14 ……強制的にInt32型にキャスト
PS > $x = "abc"
値 "abc" を型 "System.Int32" に変換できません。エラー: "入力文字列の形式が正しくありません。"
発生場所 行:1 文字:3
+ $x <<<< = "abc" ……Int32型にキャストできないためエラー
* これはPowerShellにおけるキャスト構文である。例えば、「$x = [System.Int32] 1.3」のようにすることで、右辺の値(1.3)をInt32型にキャストすることもできる。
変数に型属性を明示的に宣言することで、PowerShellは代入する値を強制的にその型にキャスト(変換)しようと試みる。上のリストを見ても分かるように、Int32型として作成された変数に小数点数を格納した場合、整数にキャストされるし、もしもInt32型に変換できないような(例えば)文字列が渡された場合にはエラーを発生する。
このようにPowerShellでは「データ型があいまいなままに使用することも、厳密にデータ型を区別して利用することも可能であること」「厳密にデータ型を指定した場合にもできるだけデータをその型に合致するように自動変換が行われること」を覚えておいていただきたい。
PowerShellでは.NET Frameworkで提供される型名をそのまま利用できるが、一部のよく利用するデータ型についてはエイリアス(別名)が用意されており、より短い型名で表記できる。以下に、PowerShellで利用可能な主な型エイリアスをまとめておく。
エイリアス | .NET Frameworkの型名 |
---|---|
byte | System.Byte |
int | System.Int32 |
long | System.Int64 |
single、float | System.Single |
double | System.Double |
decimal | System.Decimal |
char | System.Char |
bool | System.Boolean |
string | System.String |
array | System.Array |
xml | System.Xml.XmlDocument |
type | System.Type |
PowerShellの型エイリアス |
変数に格納できる重要なデータ型の1つとして「文字列」がある。PowerShellでは、この文字列を表すために、細かく分けると4種類の文字列リテラルを提供している。
ヒア・ドキュメントについては後述するとして、まず押さえておいていただきたいのは、文字列はシングルクォート/ダブルクォートのいずれかで囲む必要があるということ、そして、このいずれで囲むかによってPowerShellの挙動が異なるということだ。具体的には次の例を見てほしい。
PS > $name="山田"
PS > Write-Output "私の名前は $name です。"
私の名前は 山田 です。
PS > Write-Output '私の名前は $name です。'
私の名前は $name です。
このように、文字列に含まれる「$name」がシングルクォートで囲まれた場合にはそのまま出力されるのに対して、ダブルクォートで囲まれた場合には評価された結果(ここでは「山田」)として表示される。このように、PowerShellではダブルクォートで囲まれた文字列では「変数展開」が行われるというわけだ。
ちなみにPowerShellでは、改行文字やタブ文字のような特殊文字をエスケープ・シーケンスを利用して表現できる(以下はエスケープ・シーケンスの例だ)。
エスケープ・シーケンス | 概要 |
---|---|
`b | バックスペース |
`n | 改行 |
`r | キャリッジ・リターン |
`t | タブ |
PowerShellの文字列における主なエスケープ・シーケンス 「`(バッククォート)」記号と1文字の英字で特殊文字を表現する。多くの言語ではエスケープのために「\」記号を利用しているが、Windows OSではフォルダの区切り文字として「\」が用いられていることから、あえてバッククォート記号がエスケープ文字として採用されたようである。 |
これらエスケープ・シーケンスも、シングルクォートの中では認識されないので、要注意である。
PS > Write-Output "私の名前は`n $name です。"
私の名前は
山田 です。
PS > Write-Output '私の名前は`n $name です。'
私の名前は`n $name です。
そして、先ほど解説を保留したヒア・ドキュメント(here document)とは、(通常は複数行にまたがる)大量のテキストをスクリプト・インラインで記述するための仕組みだ。ヒア・ドキュメントは「@"<改行>〜<改行>"@」(または「@'<改行>〜<改行>'@」)の形式で記述できる。
PS > $body=@"
>> こんにちは、WINGSの山田です。
>> PowerShellの世界をご一緒に楽しみましょう。
>> "@
>> ……ここで[Enter]キーのみを入力して終了する
PS > Write-Output $body
こんにちは、WINGSの山田です。
PowerShellの世界をご一緒に楽しみましょう。
もっとも、このような例であれば、ヒア・ドキュメントという新しい仕組みを持ち出さなくても、通常のダブルクォート/シングルクォートでもよいと思われるかもしれない。事実、上の例はヒア・ドキュメントを使わずに次のように記述できる。
PS > $body="こんにちは、WINGSの山田です。
>> PowerShellの世界をご一緒に楽しみましょう。"
>>
PS > Write-Output $body
こんにちは、WINGSの山田です。
PowerShellの世界をご一緒に楽しみましょう。
しかし、以下のような例ではどうだろう。
PS > $body="こんにちは、`'WINGS`'の山田です。
>> `"PowerShell`"の世界をご一緒に楽しみましょう。"
>>
PS > Write-Output $body
こんにちは、'WINGS'の山田です。
"PowerShell"の世界をご一緒に楽しみましょう。
このように、文字列にシングルクォート/ダブルクォートを含み、かつ、ヒア・ドキュメントを利用しない場合にはクォートをエスケープする必要がある。もちろん、これは大量のテキストをインラインで記述する場合には、エスケープ漏れの原因にもなるし、そもそもエスケープが必要な個所を確認すること自体が煩雑な作業だ。そこでヒア・ドキュメントの登場というわけである。ヒア・ドキュメントは(繰り返しであるが)「@"<改行>〜<改行>"@」(または「@'<改行>〜<改行>'@」)を文字列の区切りとしているので、文字列中にクォートを自由に含めることができる。後々に文字列を変更した場合に、思わぬ不具合の原因とならないよう、複数行に及ぶ長いテキストを表す場合には(クォートの有無にかかわらず)ヒア・ドキュメントを利用することをお勧めしたい。
文字列と並び、スクリプトを記述するうえで重要なデータ型が「配列」と「連想配列(ハッシュテーブル)」である。まずはさっそく、それぞれ配列と連想配列を宣言する具体的なコードを見てみることにしよう。
PS > $x = 1,2,3
PS > Write-Output $x[0]
1 ……0番目の要素を出力
PS > $z = @{FirstName="Yoshihiro"; LastName="Yamada"; Birth="Shizuoka"}
PS > Write-Output $z["FirstName"]
Yoshihiro ……FirstName要素を出力
PS > Write-Output $z.FirstName
Yoshihiro ……FirstName要素を出力
配列/連想配列を生成する一般的な構文は、以下のとおりだ。
要素, 要素, 要素, ... ……配列
@{キー名=値; キー名=値; ...} ……連想配列
ただし配列はカンマ演算子(,)で生成するほか、以下のように記述することもできる。
@(要素, 要素, 要素, ...)
空の配列を明示的に宣言するには、単に「()」とするのではなく、「@()」のように記述する(空の連想配列を生成する場合は「@{}」)。
宣言された配列/連想配列にアクセスするには、
$変数名[インデックス番号]
$変数名["キー名"]
のように角カッコ表記でインデックス番号やキー名を指定すればよい。ただし連想配列についてはドット演算子を利用して、
$変数名.キー名
の形式で取得することも可能である(プロパティ表記)。キー名が静的に決まる場合には角カッコ表記/プロパティ表記いずれを利用しても構わないが、キー名を変数として渡したいなど動的に変更する必要がある場合には、角カッコ表記を使用する必要がある。
Copyright© Digital Advantage Corp. All Rights Reserved.