いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Powershell (pwsh) で標準入力にデータを流そうとすると謎の挙動 (stdin, get-content, -raw, -RedirectStandardInput)

概要

なんか、よく分からない状況になったので、忘れないうちにメモメモ。。。

たまたま、バイナリデータを標準入力から受け取って処理するプログラムを書いていたのですが

Powershell (pwsh) でデータを渡そうとしても

> ./app < data.bin  
ParserError: 
Line |
   1 |  ./app < data.bin
     |        ~
     | The '<' operator is reserved for future use.

なんか、エラーになった。なるほど。現状は < のリダイレクトは使えないんですね。それは仕方ない。

んで、調べると以下のようにするみたい。

> Get-Content data.bin -Raw | ./app

上のようにすると動いたのですが、なんか結果がおかしいのです。

実際のプログラムとは違いますが、以下のようなプログラムがあるとします。

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    b, _ := io.ReadAll(os.Stdin)
    fmt.Println(len(b))

    for _, v := range b {
        fmt.Printf("%02x,", v)
    }
    fmt.Println("")
}

単純に受け取ったバイト列の長さとデータを出力しているだけのプログラムがあったとします。

んで、以下のようにバイナリデータを作ったとします。

$ echo -n "0000000: 0102 0304 FFFF" | xxd -r - data.bin

hexdump で確認すると

$ hexdump data.bin
0000000 0201 0403 ffff                         
0000006

当然こうなります。んで、これを前述のプログラムにLinuxのシェル上で食べさせると

$ ./app < data.bin
6
01,02,03,04,ff,ff,

こうなる。

で、同じようにして pwsh で食べさせると

$ pwsh
PowerShell 7.2.1
Copyright (c) Microsoft Corporation.

https://aka.ms/powershell
Type 'help' to get help.

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.2.1
PSEdition                      Core
GitCommitId                    7.2.1
OS                             Linux 5.4.0-1067-azure #70~18.04.1-Ubuntu SMP Thu Jan 13 19:46:01 UTC 2022
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0


> Get-Content data.bin -raw | ./app
11
01,02,03,04,ef,bf,bd,ef,bf,bd,0a,

なんで?? 最後の 0a はLFでしょう。(動かしているのはLinuxです)

なんで改行勝手に付与すんの?ってのは置いといて FF FF の部分がなんか変わってる・・・。バイナリのサイズも変わっとるし。

stackoverflow.com

stackoverflow.com

をみると Start-Process xxxx -RedirectStandardInput xxxx.bin ってやるのがいいって書いてあるので試してみると

> Start-Process ./app -RedirectStandardInput data.bin
11
01,02,03,04,ef,bf,bd,ef,bf,bd,0a,

やっぱり駄目。

てことで、個人的には pwsh で外部プログラムに対してのパイプとかリダイレクトとかはしないほうがいいのかなって思いました。テキストデータだったら多分大丈夫なのでしょう。(勝手に改行付与されそうですが)

補足

しばたさんのブログで情報を発見。貴重な情報をアップしてくださり感謝。

blog.shibata.tech

エンコーディングが絡んでいるみたいですね。そのまま処理してくれたら嬉しいのに。。

上記のしばたさんのブログ記事でも

挙動の謎さと性能面の問題があることからPowerShellから外部のプロセスに対してパイプラインを渡すのはやめておいた方が賢明だと思います。

と書かれていました。勉強になりました m(_ _)m


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。