23

ここで少し混乱しています。ここでの私の目標は、スクリプト内のコマンドのいずれかが失敗したときに、ゼロ以外の終了コードで bash スクリプトを終了させることです。-e フラグを使用して、サブシェルを使用している場合でも、これが当てはまると想定しました。以下は簡単な例です。

#!/bin/bash -e

(false)

echo $?
echo "Line reached!"

実行時の出力は次のとおりです。

[$]>Tests/Exec/continuous-integration.sh 
1
Line reached!

Bash バージョン: CentOS の 3.2.25

4

2 に答える 2

14

これは、お使いの のバージョンに関連しているようですbash。私がアクセスできるマシンでは、bash バージョン 3.1.17 と 3.2.39 でこの動作が見られますが、bash 4.1.5 では見られません。

少し醜いですが、両方のバージョンで機能するソリューションは次のようになります。

#!/bin/bash -e

(false) || exit $?

echo $?
echo "Line reached!"

オプションのバグに関連する bash ソース変更ログにいくつかのメモがありset -eます。

于 2013-02-20T01:31:51.050 に答える
2

El Capitan より前の SuSE 11.3 と Mac OS の両方で、bash バージョン 3.2.51 でこの動作を確認しました。El Capitan の Bash 3.2.57 は、bash 4 のような「正しい」動作をします。

ただし、上記で提案された回避策は、「|| exit $?」を追加します。サブシェルの閉じ括弧の後に、bash のバージョンに関係なく、-e フラグの意図が無効になります。マンバッシュから:

-e 単純なコマンド (上記のシェル文法を参照) がゼロ以外のステータスで終了した場合、すぐに終了します。失敗したコマンドが、while または until キーワードの直後のコマンド リストの一部である場合、if ステートメントのテストの一部である場合、&& または || の一部である場合、シェルは終了しません。リスト、...

「|| exit $?」が続くサブシェル 明らかにコマンドリストとしてカウントされます。また、bash -e フラグは、サブシェル内のコマンドには適用されません。それを試してみてください:

$ set -e
$ ( echo before the error; false; echo after the error, status $?; ) || echo after the subshell, status $?
before the error
after the error, status 1
$

サブシェルの後には || が続くため、set -e を使用しても「エラー後のエコー」が実行されます。それだけでなく、その「エコー」が実行されたため、サブシェルは 0 で終了します。つまり、「|| $ を終了しますか?」「出口」さえ実行しません。おそらく私たちが望んでいたものではありません!

私の知る限り、次の式は、サブシェルの後に bash -e を受け入れるかどうかに関係なく、bash バージョンと互換性があります。-e フラグがたまたまリセットされた場合でも、正しく動作します。

bash スクリプトのすべてのサブシェルの閉じ括弧の直後に次の行を追加します。

case $?/$- in ( 0/* ) ;; ( */*e* ) exit $? ;; esac # honor bash -e flag when subshell returns
于 2015-12-18T22:57:40.793 に答える