web-dev-qa-db-ja.com

子がゼロ以外の終了コードで終了すると、親スクリプトは続行します

別のスクリプトを呼び出すスクリプトがあります。子スクリプトが失敗した場合は、親も失敗したいと思います。

子スクリプトでchild_1.sh、私はこのようなものを持っています:

if [ $SOME_BAD_CONDITION ] ; then
  echo "Error message...."
  exit 1
fi

親には、これがあります:

#!/bin/bash
set -e
#...
bash ./child_1.sh
echo "continuing to next step..."
bash ./child_2.sh
bash ./child_3.sh
#...

$SOME_BAD_CONDITIONは常に発生し、スクリプトは期待どおりに終了し、エラーメッセージdoesが出力されますが、親スクリプトは続行します。「continuing ...」というメッセージが出力され、次のスクリプトの実行が開始されます。

set -eは、ゼロ以外の終了コードを持つ子スクリプトが存在する場合、私の親スクリプトが確実に失敗するようにしますが、そうではないようです。ここで何が間違っているのかわかりません...

bashバージョン:4.2.25


更新:

エコーしてみました$?

bash ./child_1.sh
echo $?
echo "continuing to next step..."

出力は次のようになります。

エラーメッセージ.... 
 0 
次のステップに進みます... 

なぜ子の終了コードが親にならないのですか?


回答:元のコードスニペットは不完全でした。 exit 1は、ティーにパイプされたコードブロック内にありました。 clean、shortコードサンプルを投稿しようとしたが、それがどれほど重要であるかを理解していなかったため、これを無視した(bashスクリプトはまだかなり新しい)。詳細については、投稿した回答を参照してください。

したがって、子スクリプトに関する十分な詳細を投稿しないと、エラーが発生した可能性があります。この質問のために簡略化しましたが、多すぎる可能性があります。 exitステートメントがコードブロック内に埋め込まれました({および})ロギングのためにteeにパイプされました:

{
  #...
  if [ $SOME_BAD_CONDITION ] ; then
    exit 1
  fi
  #...
} | tee -a $LOGFILE
echo "script ended at $date">>$LOGFILE

私の理解から、最後のechoが0を返していたため、この子スクリプトから常に戻りコード0を受け取りました。調査を行ったところ、 $ PIPESTATUS が見つかりました。これを使用して、スクリプトが終了コード1で終了しようとしたときに、親スクリプトに渡されることを確認できました。

{
  #...
} | tee -a $LOGFILE
EXIT_CODE=${PIPESTATUS[0]}
echo "script ended at $date">>$LOGFILE
exit $EXIT_CODE

ジョンの提案と組み合わせると、うまくいくように見える解決策があります。

あなたの子プロセスは適切なゼロ/非ゼロの終了コード規則で終了し、それらを順番に実行するとすれば、&&演算子:

#!/bin/bash

./child_1.sh
[[ $? -ne 0 ]] && exit # Exit if non-zero exit code
./child_2.sh
./child_3.sh
./child_4.sh
exit 0

ここに、 [[ $? -ne 0 ]] && exitは次のように機能します:

if [ $? -ne 0 ]; then # If: last exit code is non-zero
    exit
fi

呼び出しの間に何もする必要がない場合は、使用することもできます...

#!/bin/bash
./child_1.sh && ./child_2.sh && ./child_3.sh && ./child_4
exit $?

&&演算子は ショートサーキットAND演算子 のように動作し、ゼロの終了コードはtrueブール値によく似ています。チェーン内の任意の時点で、スクリプトがゼロ以外で終了すると、&&は失敗し、後続のスクリプトは呼び出されません。

2
John WH Smith

問題は、子スクリプトでエラーをスローする方法に起因するようです。

Man setから、「単純なコマンド(上記のシェルGRAMMARを参照)がゼロ以外のステータスで終了した場合。失敗したコマンドが、テストの一部であるwhileまたはuntilキーワードの直後のコマンドリストの一部である場合、シェルは終了しません。 ifステートメント、&&または||リストの一部、またはコマンドの戻り値が!

Set -eを使用する代わりに、trapステートメントを使用してエラーをスローします。 (条件付き出口を使用する必要がある場合。

参照 http://mywiki.wooledge.org/BashFAQ/105

0
Crp