Windows PowerShellのFunction入門 (自動変数編)
この記事はWindows PowerShellのFunctionが引数を受け取る際、自動変数をの$args
、$_
、$input
を使って読み出す話です
書いておいてなんですが (というか書いて実感したのですが)、Begin
/Process
/End
ブロックを書かない (Process
ブロックのみの) Filter
を書く時に$_
を使い、それ以外の場合は自動変数を使わずにParamキィワードを使ったほうが良いです
引数名を指定せずに渡した値は$args
に配列として格納されます
Function SampleFunction1 { $args.GetType().Name; $args.Length; $args[0]; $args[0].GetType().Name; $args[1]; $args[1].GetType().Name; } PS> SampleFunction1 'a' 1; Object[] 2 a String 1 Int32
Pipelineから渡された値の受け取りは若干複雑です
Process
ブロックがある場合、$_
にその時のpipelineから渡された値が格納されます
$_
はProcess
ブロック開始前 (Begin
ブロック内) には存在していませんが、End
ブロックで読み出せます (必然的にpipelineから渡された最後の引数が格納されています)
Function SampleFunction2 { Begin{ 'Begin'; # $_; 実行するとエラーになる } Process{ 'Process'; $_; } End{ 'End'; $_; } } PS> 1,2,3 | SampleFunction2 Begin Process 1 Process 2 Process 3 End 3
次に、pipelineの値はArrayList+ArrayListEnumeratorSimple
として$input
に格納されます
Windows PowerShellではArrayList+ArrayListEnumeratorSimple
は.NETのIEnumerator インターフェイス (System.Collections)として実装されています
Windows PowerShell: These members are defined in the interface System.IEnumerator, which is implemented by the types identified below.
(中略)
Windows PowerShell: For $input, this type is System.Collections.ArrayList+ArrayListEnumeratorSimple.
$input
はBegin
ブロックでも読み出せますが値は入っておらず、何も入っていません
# 値は読み出せないが存在はしているので GetType() で型の名前は参照できる Function SampleFunction3 { Begin{ $input; $_.GetType().Name; } } PS> 1,2 | SampleFunction3 ArrayListEnumeratorSimple
Process
ブロックがあった場合、$_
と同じ値を読み出せますが、1回読み出すと読み出せなくなります
Function SampleFunction4 { Process{ $_; $input; $input; } } PS> 1,2 | SampleFunction4 1 1 2 2
Process
ブロックがなくEnd
ブロックがあった場合、$input
は全てのpipelineから渡された値を配列として持っていますが、1回読み出すと読み出せなくなります
Function SampleFunction5 { End{ $input; } } Function SampleFunction6 { End{ $input; $input; # 2回目は読み出せないので、1回のみの場合と結果が同じになる } } PS> 1,2 | SampleFunction5 1 2 PS> 1,2 | SampleFunction6 1 2
Process
ブロックとEnd
ブロックがあった場合、Process
ブロック内で読み出したかどうかに関わらず消費され、End
ブロックでは読み出せなくなっています
Function SampleFunction7 { Process{} End{ Write-Host 'End'; $input; # Processブロックがあるため何も読み出せない } } PS> 1,2 | SampleFunction7 End
ここまで長々説明しておいてなんですが、$_
はBegin
/Process
/End
ブロックを書かない (Process
ブロックのみの) Filter
をさっと書いてその場で処理する場合には便利ですが、$input
は癖があり、メンテナンス時にバグを作りこみそうな気がしますので自動変数は極力使わないのがよかろうと思います