
set -o errexit
エラーが発生すると、スクリプト全体が障害発生時点で終了するようにする bash スクリプトがあります。
スクリプトはcurl
、意図したファイルを取得できないことがあるコマンドを実行しますが、その場合、スクリプトはエラーで終了しません。
for
ループを追加しました
- 数秒間停止してから
curl
コマンドを再試行してください false
for ループの下部で使用して、デフォルトのゼロ以外の終了ステータスを定義します。curl コマンドが成功した場合、ループは中断され、最後のコマンドの終了ステータスはゼロになります。
#! /bin/bash
set -o errexit
# ...
for (( i=1; i<5; i++ ))
do
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
if [ -f ~/.vim/autoload/pathogen.vim ]
then
echo "file has been retrieved by curl, so breaking now..."
break;
fi
echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
sleep 5
# exit with non-zero status so main script will errexit
false
done
# rest of script .....
問題は、curl
コマンドが失敗すると、ループがコマンドを 5 回再試行することです。すべての試行が失敗すると、 がトリガーされるのではなく、 for ループが終了し、メイン スクリプトが再開されますerrexit
。
このステートメントが失敗した場合にスクリプト全体を終了させるにはどうすればよいですかcurl
?
答え1
交換する:
done
と:
done || exit 1
for
これにより、ループがゼロ以外の終了コードで終了した場合にコードが終了します。
トリビアとして、 は1
必要exit 1
ありません。プレーンexit
コマンドは、最後に実行されたコマンドの終了ステータスで終了しますfalse
。ダウンロードが失敗した場合は、(code=1) になります。ダウンロードが成功した場合、ループの終了コードはコマンドの終了コードになりますecho
。 echo
通常、 code=0 で終了し、成功を示します。その場合、 は||
トリガーされず、exit
コマンドは実行されません。
最後に、set -o errexit
驚きに満ちていることに注意してください。その長所と短所については、以下を参照してください。グレッグのよくある質問 #105。
ドキュメンテーション
からman bash
:
のために(( 式1 ; 式2 ; 式3 )) ;するリスト ; 終わり
まず、算術式 expr1 が、以下の算術式評価で説明する規則に従って評価されます。次に、算術式 expr2 が、ゼロに評価されるまで繰り返し評価されます。expr2 がゼロ以外の値に評価されるたびに、list が実行され、算術式 expr3 が評価されます。式が省略された場合は、1 に評価されるものとして動作します。 戻り値は、リスト内の最後に実行されたコマンドの終了ステータス、またはいずれかの式が無効な場合は false です。[強調追加]
答え2
最初の失敗時にループを停止し、 を回避したい場合はset -e
、次のようにします。
for i in `seq 1 10`; do
run_command || exit 1;
done
答え3
設定した場合errexit
、false
ステートメントによってスクリプトは直ちに終了します。コマンドが失敗した場合も同様ですcurl
。
記述されているように、サンプル スクリプトは、 errexit が設定されている場合、curl
最初に呼び出された最初のコマンドが失敗した後に終了する必要がありますfalse
。
どのように動作するかを確認するには( のショートカットを使用して-e
設定しますerrexit
):
$ ( set -e; false; echo still here )
$
$ ( set +e; false; echo still here )
still here
$
したがって、curl
コマンドが複数回実行される場合、このスクリプトはerrexit
設定されません。
答え4
set -o errexit
ループやサブシェルでは、プロセスから抜け出す方法を渡さなければならないため、扱いにくくなる可能性があります。
ループを中断することは (通常の操作であっても) 悪い習慣とみなされます。2 つの条件に対して for ループではなく while ループを好むのは古い考え方だと言われるかもしれませんが、私は次のように読む方が良いと思います。
i=1
RET=-1
while [ $i -le 5 ] && [ $RET -ne 0 ]; do
[ $i -eq 1 ] || sleep 5
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
RET=$?
i=$((i+1))
done
exit $RET