私はいくつかのシェルスクリプトを書いてきましたが、コマンドのどれかが失敗した場合にシェルスクリプトの実行を停止させることができればそれが役に立つと思います。例として以下を参照してください。
#!/bin/bash
cd some_dir
./configure --some-flags
make
make install
そのため、この場合、スクリプトが指定されたディレクトリに変更できない場合は、失敗した場合にその後に./configureを実行することは絶対に望ましくありません。
各コマンドに対してifチェックを行うことができることはわかっていますが(これは絶望的な解決策だと思います)、コマンドの1つが失敗した場合にスクリプトを終了させるグローバル設定はありますか?
set -e
ビルトインを使用してください。
#!/bin/bash
set -e
# Any subsequent(*) commands which fail will cause the Shell script to exit immediately
あるいは、コマンドラインで-e
を渡すことができます。
bash -e my_script.sh
set +e
を使ってこの動作を無効にすることもできます。
(*) 注意:
失敗したコマンドがwhileまたはuntilキーワード、ifまたはその後のテストの一部)に続くコマンドリストの一部である場合、シェルはnotを終了します。 Elif予約語、&&または||リストの最後の&&または||に続くコマンドを除く)で実行されるコマンドの一部最後のパイプライン、またはコマンドの戻り値が!)で反転されている場合
(man bash
から)
コマンドの1つが失敗したらすぐにスクリプトを終了するには、最初にこれを追加します。
set -e
これにより、テストの一部ではないコマンド(if [ ... ]
条件や&&
構文など)がゼロ以外の終了コードで終了すると、スクリプトは直ちに終了します。
これを行う方法は次のとおりです。
#!/bin/sh
abort()
{
echo >&2 '
***************
*** ABORTED ***
***************
'
echo "An error occurred. Exiting..." >&2
exit 1
}
trap 'abort' 0
set -e
# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0
echo >&2 '
************
*** DONE ***
************
'
pipefail
と組み合わせて使用してください。
set -e
set -o pipefail
-e(errexit):コマンドがゼロ以外のステータスで終了すると、最初のエラーでスクリプトを中止します(untilループまたはwhileループ、if-tests、list構成要素を除く)。
-o pipefail:パイプラインで、ゼロ以外の戻り値を返したパイプ内の最後のコマンドの終了ステータスを返します。
最初の行に収まる、受け入れられた答えに対する代替案:
#!/bin/bash -e
cd some_dir
./configure --some-flags
make
make install
1つの慣用句は次のとおりです。
cd some_dir && ./configure --some-flags && make && make install
これには時間がかかることがありますが、より大きなスクリプトでは論理関数に分割することができます。
私はあなたが探しているのはtrap
コマンドだと思います。
trap command signal [signal ...]
詳細については、 このページ を参照してください。
もう1つの選択肢は、スクリプトの先頭にset -e
コマンドを使用することです。プログラムやコマンドがtrue以外の値を返した場合は、スクリプトが終了します。
既存の回答で見逃していた1つの点は、エラートラップを継承する方法を示すことです。 bash
シェルは、set
を使用するためのそのようなオプションを1つ提供します。
-E
設定すると、
ERR
のトラップは、シェル関数、コマンド置換、およびサブシェル環境で実行されたコマンドに継承されます。ERR
トラップは通常 not から継承されています。
Adam Rosenfieldの答えset -e
を使用することの推奨は場合によっては正しいですが、それ自体に潜在的な落とし穴があります。参照 GreyCatのBashFAQ - 105 - set -e(またはset -o errexit、またはtrapのERR)が期待どおりに動作しないのはなぜですか?
マニュアルによると、set -eは終了します
単純なコマンドが0以外のステータスである場合失敗したコマンドが
while
またはuntil
キーワード、test in a if statement
の一部、&&
の一部の直後のコマンドリストの一部である場合、シェルは終了しません。||
final && or ||
、any command in a pipeline but the last
に続くコマンドを除いたリスト、または!
を介してコマンドの戻り値が反転されている場合。
つまり、set -e
は次のような単純な場合には機能しません(詳細な説明はWikiにあります)。
算術演算子let
または$((..))
(bash
4.1以降)を使用して、次のように変数値を増分します。
#!/usr/bin/env bash
set -e
i=0
let i++ # or ((i++)) on bash 4.1 or later
echo "i is $i"
問題のコマンドが、最後のコマンドのnot部分である場合は、&&
または||
を介して実行されます。例えば下の罠は予想通りには発射しないでしょう
#!/usr/bin/env bash
set -e
test -d nosuchdir && echo no dir
echo survived
if
ステートメントで誤って使用された場合、if
ステートメントの終了コードは最後に実行されたコマンドの終了コードです。以下の例では、最後に実行されたコマンドはecho
で、これはtest -d
が失敗した場合でもトラップを起動しません。
#!/usr/bin/env bash
set -e
f() { if test -d nosuchdir; then echo no dir; fi; }
f
echo survived
inherit_errexit
がbash
で設定されていない限り、コマンド置換で使用された場合、それらは無視されます。
#!/usr/bin/env bash
set -e
foo=$(expr 1-1; true)
echo survived
export
、declare
、typeset
、local
など、代入には似ているがそうではないコマンドを使用する場合。ここでf
への関数呼び出しは、local
が以前に設定されたエラーコードを一掃したため、not exitします。
set -e
f() { local var=$(somecommand that fails); }
g() { local var; var=$(somecommand that fails); }
パイプラインで使用され、問題のあるコマンドが最後のコマンドのnotの部分である場合。例えば下記のコマンドはまだ通過するでしょう。 1つの選択肢は、first failedプロセスの終了コードを返すことによってpipefail
を有効にすることです。
set -e
somecommand that fails | cat -
echo survived
理想的な推奨はnotを使いset -e
を使い、代わりに独自のバージョンのエラーチェックを実装することです。 Bashスクリプトでエラーを発生させる - の私の答えの1つにカスタムエラー処理を実装することに関するさらなる情報