パイプを使用するときに終了状態を渡す方法を理解しようとしています。which
存在しないプログラムを見つけるために使用しているとします。
which lss
echo $?
1
私のシャットダウンステータスは、検索にwhich
失敗したため1です。lss
これはいいですね。しかし、次のようにしようとすると:
which lss | echo $?
0
これは、最後に実行されたコマンドが正常に終了したことを示します。私が理解できる唯一の方法は、PIPEが終了ステータスを生成できることです。これは正しい理解方法ですか?
ベストアンサー1
パイプの終了状態は右コマンドの終了状態です。左コマンドの終了状態は無視されます。
(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
。
- クッシュ:
set -o pipefail
- 大きな打撃:
shopt -s pipefail
- zsh:(
setopt pipefail
またはsetopt pipe_fail
)
PIPESTATUS
mksh、bash、およびzshでは、最後のパイプライン(一般化)pipestatus
のすべてのコマンド状態を含む配列である変数(bash、mksh)または(zsh)を使用して、パイプラインの各コンポーネントの状態を取得できます。$?