パイプの終了ステータスは、右側のコマンドの終了ステータスです。左側のコマンドの終了ステータスは無視されます。
(which lss | echo $?
これは表示されないことに注意してくださいwhich lss | true; echo $?
。これを表示するには、を実行します。ではwhich lss | echo $?
、echo $?
このパイプラインの前の最後のコマンドのステータスを報告します。)
シェルがこのように動作する理由は、左側のエラーを無視すべきかなり一般的なシナリオがあるためです。左側がまだ書き込み中に右側が終了する(または、より一般的には標準入力を閉じる)場合、左側はSIGPIPEシグナルを受信します。この場合、通常は何も問題はありません。右側はデータを気にしません。左側の役割がこのデータを生成することのみである場合は、停止しても問題ありません。
ただし、左側がSIGPIPE以外の何らかの理由で死亡した場合、または左側のジョブが標準出力でデータを生成することだけではなかった場合、左側のエラーは真のエラーであり、報告する必要があります。
プレーンなshでは、唯一の解決策は名前付きパイプを使用することです。
set -e
mkfifo p
command1 >p & pid1=$!
command2 <p
wait $pid1
ksh、bash、およびzshでは、パイプラインのいずれかのコンポーネントがゼロ以外のステータスで終了する場合、パイプラインをゼロ以外のステータスで終了するようにシェルに指示できます。pipefail
オプションを設定する必要があります:
- ksh:
set -o pipefail
- bash:
shopt -s pipefail
- zsh:(
setopt pipefail
またはsetopt pipe_fail
)
mksh、bash、zshでは、変数PIPESTATUS
(bash、mksh)またはpipestatus
(zsh)を使用して、パイプラインのすべてのコンポーネントのステータスを取得できます。これは、最後のパイプラインのすべてのコマンドのステータスを含む配列です(一般化$?
)。
which lss | echo $?
、は終了するecho
前which
に開始されます。のコマンドラインを生成するシェルecho
にwhich
は、後で終了ステータスがどうなるかを知る方法がありません。