前のエントリの続き的な。
PowerShellが外部のプロセスにパイプラインでデータを渡す際は、
コンソールに出力される文字列を
$OutputEncoding
に設定されているエンコーディングでエンコードした文字列を渡している・・・(中略)・・・
また、文字列でないオブジェクトについてはコンソールには
Format-Table
した結果が出力されます。
このためオブジェクトを標準入力(StdIn)に渡すとFormat-Table
した結果の文字列が渡されることになります。
と言いましたが、実際どんなふうになっているかを確かめてみるのが今回のエントリになります。
特に環境依存な部分はないと思いますがWindows 8.1上で確認しています。
検証プログラム
検証用に簡単なプログラムGetPipeline.exe
を用意しました。
これは単純に標準入力に受け取ったデータを16進表示するだけのプログラムです。
using System; namespace GetPipeline { class Program { static void Main(string[] args) { var StdIn = Console.OpenStandardInput(); var Buffer = new byte[1024]; var Reads = 0; while ((Reads = StdIn.Read(Buffer, 0, Buffer.Length)) > 0) { for (int i = 0; i < Reads ; i++) { Console.Write(Buffer[i].ToString("X2")); Console.Write(' '); } } Console.WriteLine(); } } }
文字列を渡した場合
最初にデフォルトの$OutputEncoding=[Text.Encoding]::ASCII
の状態で適当な文字列Hello!
をパイプラインで渡してみます。
# $OutputEncoding=[Text.Encoding]::ASCII PS C:\Temp> "Hello!" | .\GetPipeline.exe 48 65 6C 6C 6F 21 0D 0A
Hello!(48 65 6C 6C 6F 21)
の後にCRLF(0D 0A)
がついていることがわかります。
次にひらがなであ
を渡してみます。
# $OutputEncoding=[Text.Encoding]::ASCII PS C:\Temp> "あ" | .\GetPipeline.exe 3F 0D 0A
ASCIIコードではあ
は表現できないため文字化けした結果?(3F)
とCRLF(0D 0A)
が渡されていることがわかります。
続けて$OutputEncoding=[Text.Encoding]::Default (MS932)
するとどうなるか確かめてみます。
PS C:\Temp> $OutputEncoding = [Text.Encoding]::Default PS C:\Temp> "あ" | .\GetPipeline.exe 82 A0 0D 0A
するとあ
が?
に化けることなくあ(82 A0)
として渡される様になりました。
文字列以外を渡した場合
文字列以外のデータを渡した場合どうなるかを見ていきます。
数値の場合
# $OutputEncoding=[Text.Encoding]::ASCII PS C:\Temp> [int]123 | .\GetPipeline.exe 31 32 33 0D 0A PS C:\Temp> [Double]12.3 | .\GetPipeline.exe 31 32 2E 33 0D 0A PS C:\Temp> 10 / 3 | .\GetPipeline.exe 33 2E 33 33 33 33 33 33 33 33 33 33 33 33 33 33 0D 0A # 10 / 3 の計算結果は 3.33333333333333 とコンソールに表示される。
数値を文字列にして渡しています。
Bool型の場合
# $OutputEncoding=[Text.Encoding]::ASCII PS C:\Temp> $true | .\GetPipeline.exe 54 72 75 65 0D 0A PS C:\Temp> $false | .\GetPipeline.exe 46 61 6C 73 65 0D 0A
True
およびFalse
の文字列が渡されます。コンソールに表示される内容と同じです。
NULLの場合
# $OutputEncoding=[Text.Encoding]::ASCII PS C:\Temp> $null | .\GetPipeline.exe
この場合は何も渡されません。
その他の型の場合
最後にls(Get-ChildItem)
コマンドの結果で試してみます。
今回の例ではls
を実行すると以下の様な結果になります。
PS C:\Temp> ls ディレクトリ: C:\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2015/06/27 20:15 5120 GetPipeline.exe
コンソールには上の様に表示され、コマンドの実行結果は、今回は1ファイルのみが取得されているのでSystem.IO.FileInfo
クラスのオブジェクトが返されています。
これをふまえてパイプラインで渡した結果を確認してみます。
# コンソールの表示結果に日本語があるため$OutputEncodingを変えている PS C:\Temp> $OutputEncoding = [Text.Encoding]::Default PS C:\Temp> ls | .\GetPipeline.exe 0D 0A 0D 0A 20 20 20 20 83 66 83 42 83 8C 83 4E 83 67 83 8A 3A 20 43 3A 5C 54 65 6D 70 0D 0A 0D 0A 0D 0A 4D 6F 64 65 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4C 61 73 74 57 72 69 74 65 54 69 6D 65 20 20 20 20 20 4C 65 6E 67 74 68 20 4E 61 6D 65 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 0D 0A 2D 2D 2D 2D 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 20 20 20 20 20 2D 2D 2D 2D 2D 2D 20 2D 2D 2D 2D 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 0D 0A 2D 61 2D 2D 2D 20 20 20 20 20 20 20 20 32 30 31 35 2F 30 36 2F 32 37 20 20 20 20 20 32 30 3A 31 35 20 20 20 20 20 20 20 35 31 32 30 20 47 65 74 50 69 70 65 6C 69 6E 65 2E 65 78 65 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 0D 0A 0D 0A
これ、ちょっと長ったらしいのですが、コンソールに帰ってきた文字列
ディレクトリ: C:\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2015/06/27 20:15 5120 GetPipeline.exe
の部分を返しています。
おまけ
ちなみに、コンソールに表示される文字列が渡されるということでWrite-Host
した結果をパイプラインで渡すとどうなるかというと、
こんな感じでコンソールに文字は出力されますが外部プロセスには何も渡されません。
まあ、当然の動作ではありますが一応確認ということで。
とりあえずこんな感じでした。