前のコマンドが失敗した場合にパイプラインを終了する

前のコマンドが失敗した場合にパイプラインを終了する

qstat -tn1スクリプトの出力を解析して、実行中およびキューに入れられた PBS ジョブの数を確認しようとしていますbash。これまでのところ、これは機能しています:

count ()
{
    qstat -tn1 | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

しかし、 が不明な理由で失敗することがありますqstat。その場合、 には何も出力されずstdout、 に何らかのエラー メッセージが出力されstderr、非ゼロのステータス (かなり標準的) で終了します。ただし、 は失敗したawkことを認識せずqstat0 0受け取った空の入力に対して を正常に出力します。次に、が実際に失敗したことを認識せずに、 とreadの両方に 0 を割り当てます。RQqstat

  1. 実行中のプロセスやキューに入れられたプロセスがない可能性があるため、スクリプトのブロックで と を 0 でR初期化する必要があります。また、そのようなプロセスの数として、空の文字列だけでなく を印刷する必要があります。QBEGINawk0
  2. を実行すると、ゼロ以外のステータスで終了set -o pipefailできますが、終了ステータスを確認できず、とにかく実行されて空の入力が出力されます。countreadawk0 0
  3. 名前付きパイプとサブプロセスを試すこともできますが、それらを管理するのは複雑すぎてやり過ぎのように感じます。

countの呼び出し側が障害を検出できるようにする良い方法はありますか?

答え1

プロセス置換を読み込むと、戻りステータスを取得できなくなると思いますcount。そのため、そうしないでください。代わりに、結果を変数に格納するか、パイプを使用してください。

count=$(count)
if [ $? -eq 0 ]; then
  read -r R Q <<<"$count"

または

set -o pipefail
if count | { read -r R Q; … }

もう 1 つの可能性は、変数を使用してPIPESTATUS最初のコマンドの戻りステータスを確認することです。

count=$(qstat -tn1 | awk …)
if ((${PIPESTATUS[0]} == 0)); then
  read P Q

あるいは、入力が空の場合に awk が何か特別なもの (たとえば何も出力しない) を出力するように設定します。

awk '
    BEGIN { R = 0; Q = 0; }
    $10 == "R" { R++ }
    $10 == "Q" { Q++ }
    END { if (NR) print R, Q }'

コマンドの入力が空かどうかをテストするにはifneもっと見るまたはその他の方法ただし、awk にパイプするのであれば、既存の awk スクリプト内で直接実行したほうがよいでしょう。

コマンドからの戻りステータスを取得する必要がある場合はqstat、それを追加の入力行として awk に渡すことができます。解析を容易にするために、最後の行が一意の形式になるように調整します。

{
  qstat -tn1
  echo exit_code = $?
} | awk '
    /^exit_code = / { status = $3 }
    END { if (status == 0) print Q, R }
'

答え2

これ:

count ()
{
    { qstat -tn1 || echo "EPIC FAIL" } | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

が成功した場合、qstatその出力は に送信されますawk。 がqstatゼロ以外のステータスを返す場合、テキスト「EPIC FAIL」が に送信されますawk

これは単なる例です。 echo を、 内部awkまたは で処理できる適切なものに置き換えてくださいif read

関連情報