stdinで読むことはbashとzshで異なる動作をします。

stdinで読むことはbashとzshで異なる動作をします。

コマンドの出力をシェルの組み込み関数にパイプしようとしていますが、read動作が異なります。zshbash

$ bash -c 'echo hello | read test; echo $test'

$ zsh -c 'echo hello | read test; echo $test'
hello

この方法はでは機能しませんが、bash次の方法は両方に機能します。

 $ bash -c 'echo hello | while read test; do echo $test; done'
 hello
 $ zsh -c 'echo hello | while read test; do echo $test; done'
 hello

なぜそんなことですか?私が間違って使用したのでしょうかread?私はこれをスクリプトで使用することがtest="$(echo hello)"参照問題をより注意深く扱うように強制するよりも読みやすくなることがわかりました。

ベストアンサー1

POSIXを使用して標準化されていない結果を観察しています。

POSIXは、インタプリタがパイプラインを実行する方法を標準化しません。

有名なBourne Shellの場合、パイプラインの一番右のプログラムはメインシェルのサブルーチンではありません。その理由は、この実装が遅いですが、コードがほとんど必要ないためです。これは、メモリが64kBしかない場合に重要です。このバリアントでは、readコマンドは子プロセスで実行されるため、子プロセスに割り当てられたシェル変数はデフォルトのシェルには表示されません。

kshあるいは、(最近ではBourne Shell)などの最新のシェルは、boshパイプ内のすべてのプロセスがプライマリシェルの直接のサブアイテムになるようにパイプを作成し、右側のプログラムが組み込みシェルの場合はデフォルトシェルによって実行されます。シェル。

これらすべては、readプログラムがメインシェルのシェル変数を変更できるようにするために必要です。したがって、このバリアント(最速)でのみデフォルトシェルで変数の割り当て結果を表示できます。

2番目の例では、ループwhile全体が同じ子プロセスで実行されるため、変更されたバージョンのシェル変数を印刷できます。

現在、パイプされたコマンドにゼロ以外の終了コードがあるかどうかに関する情報を取得するために、POSIXシェルのサポートを追加するように求められます。これを達成するには、パイプライン内のすべてのプログラムがメインシェルの直接サブルーチンになるようにシェルを実装する必要があります。許容レベルに近い。

echo foo | read val; echo $val

予想される操作が実行され、その時点からプライマリシェルで読み取りを実行するための要件のみが欠落しています。

おすすめ記事