このようなBashスクリプトのパイプラインを作りたいです
prog1 | prog2
そのため、prog2はprog1の終了コードを確認し、その情報に基づいて異なる動作をすることができます。
これは可能ですか?
prog2
、prog1
終了時の進行状況の制御が制限されます。prog1
prog2
このようなBashスクリプトのパイプラインを作りたいです
prog1 | prog2
そのため、prog2はprog1の終了コードを確認し、その情報に基づいて異なる動作をすることができます。
これは可能ですか?
prog2
、prog1
終了時の進行状況の制御が制限されます。prog1
prog2
回答:
一般的な答えはノーです。それは可能だprog2
前に終了するにはprog1
(あれば、明らかにそれが起こることができないでも開始prog2
、実際にあなたがパイプラインでそれを使用している場合、それが何を期待したいいくつかの入力を、読み込みます)。prog2
前に終了することは間違いなく可能ですprog1
。これは、たとえばprog2
、一致が見つかるとすぐに終了する検索プログラムの場合に発生します。この場合、prog1
まだすべてのデータの生成が完了していない可能性があります。
prog2
の終了ステータスを取得しprog1
たり、終了したことを知る直接的な方法はありませんprog1
。prog2
知ることができるすべてはそれprog1
が死ぬことなく行うことができるパイプの端を閉じたことです。
prog1
from の終了ステータスを取得する場合prog2
、2つの一般的な方法があります。ファイルに書き込むか、パイプを介して送信することができます。パイプされたデータの最後の行として出力ステータスを送信することは可能です。最終行であることを確認するまで、つまり次の行を読み取ろうとするまで、最終行を処理しないようにする必要があります。
{ prog1; echo $?; } | …
右側がテキストフィルターで、「エラー」という単語を含むすべての行を赤で着色する例です。左側が失敗した場合、右側は同じステータスで終了します。
{ prog1; echo $?; } | awk '
NR != 1 {
if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m";
else print line;
}
{line = $0}
END {exit($0)}
'
${PIPESTATUS[@]}
、の出力で何よりも前にソートされている場合にのみ機能しますcommand
。command
が大量の数字を出力する場合、または任意のテキストを出力できる場合は、困っています。出力とステータス行を区別できません。
いくつかの特別なケースでは可能ですが(他の回答を参照)、すべてのケースでできるわけではありません。一部のフィルタープログラムはそのまま続行しますが、他のフィルタープログラムはすべての出力を保持し、一度に解き放ってから終了します。
「そのまま続ける」プログラムの例としては、grep
サーバーがそうであるようにtail -f /var/log/some_log_file
。sort
パイプラインで使用すると、sort
その前のパイプが閉じるまで入力が収集されるため、「ストール」が発生します。使用xargs
するとさらに複雑になります。プログラムxargs
はパイプラインの一部(多くのインスタンスを開始する可能性があります)によって開始されますか?
答え:直接ではありません。
@terdonは、パイプ内の前のコマンドの終了コードを明示的なパラメーターとして次のコマンドに送信する必要があることを示しています。
パイプは、前のコマンドのSTDOUTから次のコマンドのSTDINへのマッピングにすぎないことに注意してください。終了コードはSTDOUT(またはSTDERR)に出力されません。
パイプライン内のすべてのプロセスは、終了する前に開始されます。したがってprog2
、開始後にこの情報を取得する必要があり、prog1
終了するまで処理を保留する必要があり、パイプが停止する可能性があります。OSの制限ではなく、要求したことを行う上で基本的な問題があるようです。
おそらく、一時ファイルを検討するか、結果を変数に入れる必要があります。
変数を使用した少量のデータの例。
tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
…
else
…
fi
prog2
はprog1
通常、完了する前に開始されますが、prog1
実行中に出力ステータスを受け取る方法がある可能性があります。