2017-01-17 13 views
2

のようなパイプラインの何かを考えると、 "A | B | C | D | E"、私はこのような工程Bの何かの結果にステップCを条件付きにしたい:条件付きステップ

A | B | if [ $? -ne 0 ]; then C; else cat; fi | D | E 

しかし、これは動作していないようです。 Bの結果に関係なく、Cは決して実行されません。私はより良い解決策を探しています。

私はパイプラインの各ステップがそれ自身のサブシェルで実行されることを理解します。だから私はパイプラインに戻って環境変数を渡すことはできません。しかし、このパイプラインはGnu並列環境にあり、多くのパイプラインが同時に実行されており、データストリームだけを処理し、ソースを知る必要はなく、親スクリプトが必要な分離を処理します。これは、ファイル名を一意にする方法がないため、一時ファイルを使用することも実用的ではないことを意味します。 $$でも各ステップで同じ価値があるとは思われません。

+0

'set -o pipefail'を見るかもしれませんが、より現実的には、単一のパイプラインを使うのではなく、コマンドを分割するだけです。 –

答えて

4

コマンドが並列に実行されるため、パイプラインを条件付きにすることはできません。 Cが終了してBが終了するまで、Bの出力はどこにパイプされますか?

Bの出力を変数または一時ファイルに保存する必要があります。たとえば、

out=$(mktemp) 
trap 'rm "$out"' EXIT 
if A | B > "$out"; then 
    C < "$out" 
else 
    cat "$out" 
fi | D | E 
+0

これは私が必要とした解決策のようです。ありがとう。 –

+0

'export -f'関数に入れて、GNU Parallelのために用意されています –

+0

' mktemp'と 'trap'の代わりに$ PARALLEL_TMPを使うことができます。 –

1

問題の状態を論理的に表すことはできません。

A | Bのようなパイプを仮定します。パイプラインは、Aが終了する前にBがAから読み始めるようにするために特に存在します。だからBが始まるとき(あなたの状態が評価されるとき)、Aはそれが失敗するか、成功するかはまだ分からないので、Bもどちらも知ることができません。

あなたができることは、エコーを最後の行として、ある種類のステータスコードを持つことです。その後、Bは標準入力から読み込み、入力を一時ファイルとして変数に保存してから、最後の行を受け取ったらステータスを確認してから処理を実行できます。

それ以外の方法はもちろん、Aは独自の出力を格納し、それが終了すると条件付きの内部を持つ(そしてパイプラインからBを取り除く)。

+0

ああ...もちろん...時々私は細部に迷ってしまいます。パイプラインの仕組みを思い出させてくれてありがとう。 –