概要
説明が長くなりそうなので分割。 ここでは、主に変数の取り扱いについて説明します。
変数
「基礎知識」でも説明したように、 $ から始まる単語は変数になります。
> $a = 1 > $a 1
「$ + アルファベット」という書き方以外に、 「${任意の記号}」という書き方もできます。 ${a} というように、中身がアルファベットなら $a と同じ意味になってあまり意味はないんですが、 ${#$%&'(} というような、任意の記号を含む変数名を付けることができます。
Variant ではなく Object
変数にはどんな型の値でも代入できますが、 Variant ではなく Object です。
(Variant ってのは、要するに、 「型の定まってない型」、「どんな型にでもなれる型」です。 型があいまいになるのでプログラミングミスの原因。 あと、型判定とか型変換のためのオーバーヘッドも生じる。 Object の方は、 C 言語的にいうと (void *) みたいなもので、 どんな型の値も格納できるものの、 中身の型が変わることはありません。 )
Object の中身はちゃんと型を持っています。 1 を代入したなら System.Int32 ですし、 "test" を代入したなら System.String になります。 PowerShell 上のオブジェクトは全て .NET Framework のオブジェクトで、 GetType() などのメソッドやプロパティを使うことができます。
( ただ、数値や文字列に対しては Variant 的な動作をしていて、 特殊な自動変換が働いて「どんな型にでもなれる型」になっています。 でも、特殊な型変換機構が働くのは、数値や文字列などの基本的な型のみ。 それ以外の型に関しては、暗黙的コンストラクタ呼び出しで型変換をしているみたい。 )
( あと、C# でいうところの unboxing は自動的にやってくれるので、 object a = "test"; ((string)a).ToUpper(); みたいなキャストは必要ありません。 )
> $a = 1 > $a.GetType().Name Int32 > $a = "test" > $a.Length 4 > $a.ToUpper() TEST > $a.GetType().Name String
オブジェクトが全部 .NET Framework のものなので、 .NET Framework SDK のヘルプを読むことで、 数値や文字列に対してどういう操作が可能なのかとかを調べることができます。
型変換
値や変数の前に [型名] を付けると、型変換ができます。 例えば、実数を整数に変換するには以下のようにします。
> $a = [int]1.2 > $a 1
無理な変換をしようとするとエラーになります。
> $a = [int]"test"
値 "test" を型 "System.Int32" に変換できません。
でも、結構柔軟に型変換してくれます。 例えば、"128" というような文字列は、 C# なんかだと int.Parse メソッドを使って整数に変換する必要がありますが、 PowerShell では [int] で変換できます。
> $a = [int]"128" > $a 128 > $a.GetType().Name Int32
型の指定
変数の型は明示的に指定することもできます。 指定方法は、例えば以下のような感じで、 代入時に [型名] を変数の前に付けます。
> [int]$a = 1
型を指定すると、指定した型以外は代入できなくなります。
> [int]$a = 0 > $a = "test" # ↓ エラー 値 "test" を型 "System.Int32" に変換できません。 > $a = 1.1 # ↓ 整数に型変換される > $a 1
一度型を指定すると、その変数はもうずっとその型の値しか代入できません。 別の型の値を代入したければ、 後述する 「Remove-Variable」 Cmdlet でいったん変数を削除する必要があります。
型
先ほども説明したように、 PowerShell 上のオブジェクトは全て .NET Framework のオブジェクトになっています。 整数なら System.Int32 ですし、 小数なら System.Double、 文字列なら System.String です。
ただし、PowerShell では System 名前空間は省略可能です。 あと、大文字と小文字を区別しないので、 それぞれ、int32, double, string という名前で型を指定できます。
また、System.Int32 には int、 System.Int64 には long、 System.Boolean には bool という別名が付いています。 (どうもこの3つだけっぽい。 uint や short はない。 UInt32 や Int16 と書く必要あり。)
あと、特殊な型 void というものがあるようです。 (void は C 言語や C# などで、関数の戻り値がないことを示すキーワード。) [void] を使うと、値を消してしまうことができるみたい。
> [void]1 > [void]$a > [void]$a.GetType()
まあ、この例みたいな使い方にはあまり意味はありませんが、 関数(例えば、実行の成否を bool で返してくるような)の戻り値を無視したいときなどに使います。
スコープ
- PowerShell の変数はスコープを持っています。
- 普通に宣言した変数はローカルスコープを持っていて、
- 関数やブロックの外部からは参照できません。
-
をはさんで変数名の前にスコープ名を書くことで、 ローカル以外のスコープの変数を読み書きできます。 (例えば、グローバルスコープの変数 a には、 $global:a という書き方でアクセスする。)
スコープは以下の4種類あります。
グローバル | global | どこからでも(スクリプトファイル外からでも)読み書き可能 |
---|---|---|
スクリプト | script | 同一スクリプトファイル内なら、どこからでも読み書き可能 |
ローカル | local | 現在のブロック内か、子ブロック(ブロック中にさらにブロックを書く)から読み書き可能 |
プライベート | private | 現在のブロック内からのみ読み書き可能(子要素も除く) |
また、これらの名前付きスコープの他に、 別項で説明する 「Set-Variable」, 「Set-Variable」 Cmdlet を使うと、 「2レベル上の親ブロック中のスコープ」というように、 レベルを指定しての変数の読み書きも可能です。
あと、スコープとは違うんですが、 スコープと同じような「$env:変数名」という書式で環境変数を取得することもできます。 例えば、path 環境変数を取得したければ以下のように書きます。
> $env:path
C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Wind....
↑どうも、env: はファイルシステムのドライブとかと同列の扱いらしい。 C ドライブを C: とか書くのと同じ。 で、「${C:...\ファイル名}」みたいな記法で、ファイルの読み書きもできる模様。
> ${C:\Users\Public\test.txt} = "test" > ${C:\Users\Public\test.txt} "test" > Get-Content C:\Users\Public\test.txt "test"
ただし、 C:\ からフルパス書かないと駄目みたい。 (要するに、構文としては ${ドライブレター:パス} でないと駄目。) まあ、あんまり便利な記法にも見えないし、 普通に Get-Content, Set-Content を使った方がいいかも。
演算子
整数の加減乗除・剰余に関しては、
C# と同じ
+ - * / %
という記号を使って演算が可能です。
また、文字列にも + や * 演算子が使えます。
(詳しくは次節で説明。)
これら5つの演算子に対しては、
対応する代入演算子
+= -= *= /= %=
も存在します。
($a = $a + 1 と $a += 1 は同じ意味。)
ちなみに、代入演算子は複数並べて書くこともできます。
> $a = $b = $c = 1 > $a,$b,$c 1 1 1 > $a += $b += $c += 1 > $a,$b,$c 4 3 2
一方、
& や > などの記号は特殊な意味を持っているので、
+ - * / %
の5つ以外に関しては
「-eq」や「-lt」というように、
- から始まる文字列を使って演算子を表します。
Object に対する演算子
整数や文字列、配列に対する演算子は、 それぞれの項で説明するとして、 ここでは任意の型に共通する演算だけ説明しておきます。
まず、変数が存在するかどうかを確認するために、 -eq 演算子を使って null 値との比較が可能です。 null というのは変数が空っぽの状態のことで、 PowerShell では、$null という名前の特殊な変数で表します。
> Remove-Variable a > $a > $a -eq $null True > $a = 0 > $a -eq $null False
ちなみに、$() とか [void]0 でも null 値を作ることができたりします。
それから、-is と -isnot 演算子を使って、変数に格納されている値の型を確かめることができます。 (左辺に変数、右辺に [型名] を書きます。)
> $a = 1 > $a -is [int] True > $a -isnot [int] False > $a -is [string] False > $a -isnot [string] True
また、-as で型変換もできます。 [型名] による型変換とちがって、 変換できない場合にはエラーを起こすのではなく null 値を返します。
> $a = "test" -as [int] > $a -eq $null True > $a = 1.2 -as [int] > $a 1
演算子の優先順位
演算子には結合の優先度があります。 例えば、(まあ、多くのプログラミング言語がそうであるように、) + より * の方が優先度が上で、 1 + 2 * 3 + 1 と書くと 1 + (2 * 3) の意味になります。
まだ現時点で説明していない演算子もありますが、 とりあえずリファレンスに書いてある優先度一覧を示します。
優先度 | 演算子 | 補足 |
---|---|---|
高 | ( ) { } | |
@ | 配列生成 | |
$ | 変数、式評価演算子 | |
! | 論理否定 | |
[ ] | 配列インデックス | |
. | メンバー参照の . | |
& . | 実行演算子、ソース演算子 | |
++ -- | ||
単項 + - | ||
, | 配列化† | |
.. | 配列化† | |
* / % | ||
2項 + - | ||
比較演算子 | †† | |
-band -bor -bxor | † | |
-and -or | ||
| | パイプライン | |
> >> | リダイレクト | |
低 | 代入演算子 |
† リファレンスには書いてないけど、多分この位置
†† 多分、-as -is -replace -contains -f は比較演算子のところに含まれてると思う。
シェル変数
PowerShell が既定で持っている変数(シェル変数)がいくつかあります。
自動変数
いくつか、PowerShell 自体が自動的に値を設定している自動変数があります。 (ユーザは変更できない。)
「Get-Variable」 Cmdlet を引数なしで呼び出せば、 現在使われている変数一覧が取得できるので、 PowerShell を起動直後に Get-Variable すればどういう自動変数があるのかが分かります。
以下、いくつか代表的なものを挙げます。 (詳細は、Get-Help Cmdlet を使って「Get-Help about_automatic_variables」で見れます。)
変数名 | 説明 |
---|---|
$$ | 前のコマンド ラインの最後のトークン。 |
$^ | 前のコマンド ラインの最初のトークン。 |
$? | 最後のコマンドの論理値状態。 |
$_ | 現在のパイプライン オブジェクト。 |
$args | スクリプトまたは関数の引数。 |
$input | スクリプトにパイプで連結されているオブジェクトの列挙子。 |
$Matches | -match 演算子で検出された一致結果の連想配列。 |
$HOME | ユーザーのホーム ディレクトリ。 |
$Error | 前のコマンドのエラーの配列。 |
$MyInvocation | スクリプトファイル自身に関する情報 |
ユーザ設定変数
履歴の最大保持数など、 ユーザが設定できるシェル変数(ユーザ設定変数)もあります。