パイプラインの次のプログラムは、前のプログラムの終了コードを見ることができますか?


8

このようなBashスクリプトのパイプラインを作りたいです

prog1 | prog2

そのため、prog2はprog1の終了コードを確認し、その情報に基づいて異なる動作をすることができます。

これは可能ですか?


質問の別の部分で、行為について詳しく説明してもらえますか?
devnull 2014年

パイプを実装するために使用される内部バッファリングと、どのように、どのようにスケジュールされるかによりprog2prog1終了時の進行状況の制御が制限されます。prog1prog2
chepner 2014年

また、[?どのような順序でパイプされたコマンドを実行しない](unix.stackexchange.com/q/37508)を見て
DKボーズ

回答:


4

一般的な答えはノーです。それは可能だprog2前に終了するにはprog1(あれば、明らかにそれが起こることができないでも開始prog2、実際にあなたがパイプラインでそれを使用している場合、それが何を期待したいいくつかの入力を、読み込みます)。prog2前に終了することは間違いなく可能ですprog1。これは、たとえばprog2、一致が見つかるとすぐに終了する検索プログラムの場合に発生します。この場合、prog1まだすべてのデータの生成が完了していない可能性があります。

prog2の終了ステータスを取得しprog1たり、終了したことを知る直接的な方法はありませんprog1prog2知ることができるすべてはそれprog1が死ぬことなく行うことができるパイプの端を閉じたことです。

prog1from の終了ステータスを取得する場合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)}
'

{ command; echo ${PIPESTATUS[@]}; } | sort | ...ストリームで終了ステータスが最初になるようにしようとしました。とても面白いです!

@illuminÉこれは${PIPESTATUS[@]}、の出力で何よりも前にソートされている場合にのみ機能しますcommandcommandが大量の数字を出力する場合、または任意のテキストを出力できる場合は、困っています。出力とステータス行を区別できません。
Gilles「SO-悪をやめる」14年

ありがとう、実際、コマンドの出力lolに0が含まれていない場合にのみ、成功ステータスを最上位にソートできます。Tgif / s。

2

いくつかの特別なケースでは可能ですが(他の回答を参照)、すべてのケースでできるわけではありません。一部のフィルタープログラムはそのまま続行しますが、他のフィルタープログラムはすべての出力を保持し、一度に解き放ってから終了します。

「そのまま続ける」プログラムの例としては、grepサーバーがそうであるようにtail -f /var/log/some_log_filesortパイプラインで使用すると、sortその前のパイプが閉じるまで入力が収集されるため、「ストール」が発生します。使用xargsするとさらに複雑になります。プログラムxargsはパイプラインの一部(多くのインスタンスを開始する可能性があります)によって開始されますか?


-1あなたが間違った答えを合理化するために賛成したので。
ctrl-alt-delor 2014年

@richard Huh?ブルースの答えは正しいです(2番目の段落は少し混乱しますが)。
Gilles「SO-邪悪なことをやめなさい」2014

1

答え:直接ではありません。

@terdonは、パイプ内の前のコマンドの終了コードを明示的なパラメーターとして次のコマンドに送信する必要があることを示しています。

パイプは、前のコマンドのSTDOUTから次のコマンドのSTDINへのマッピングにすぎないことに注意してください。終了コードはSTDOUT(またはSTDERR)に出力されません。


1
-1あなたは間違った答えを引用し、それ以上は言っていないことに賛成したからです。
ctrl-alt-delor 2014年

@richardはかなり公正です...私は再確認する必要がありました...非常に疲れたときに質問に答えるように自分を強制した場合に起こりました...
pepoluan 14年

1

パイプライン内のすべてのプロセスは、終了する前に開始されます。したがってprog2、開始後にこの情報を取得する必要があり、prog1終了するまで処理を保留する必要があり、パイプが停止する可能性があります。OSの制限ではなく、要求したことを行う上で基本的な問題があるようです。

おそらく、一時ファイルを検討するか、結果を変数に入れる必要があります。

変数を使用した少量のデータの例。

tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
   
else
   
fi

あなたの推論にはギャップがあります。prog2prog1通常、完了する前に開始されますが、prog1実行中に出力ステータスを受け取る方法がある可能性があります。
Gilles「SO-邪悪なことをやめよう」14年

0

Gillesの回答を終了するには、

(prog1; echo $? > /tmp/prog1.status) | prog2

アプローチです。  prog2どちらか

  • 標準入力を最後まで読み取り/tmp/prog1.status、次に、または
  • /tmp/prog1.status標準入力を読み取りながら、定期的にの存在を確認してください。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.