コマンドの出力をシェルの組み込み関数にパイプしようとしていますが、read
動作が異なります。zsh
bash
$ 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
予想される操作が実行され、その時点からプライマリシェルで読み取りを実行するための要件のみが欠落しています。