パイプの終了ステータスは、右側のコマンドの終了ステータスです。左側のコマンドの終了ステータスは無視されます。
(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は、後で終了ステータスがどうなるかを知る方法がありません。