
私は、ERR トラップを使用して、bash スクリプト内のエラーをキャッチし、発生したエラーをログに出力しています。(この質問に似ています:トラップ、ERR、エラー行のエコー) 期待どおりに動作します。唯一の問題は、スクリプトのある時点で exitcode !=0 が発生することが予想されることです。この状況でトラップがトリガーされないようにするにはどうすればよいですか?
ここにコードがあります:
err_report() {
echo "errexit on line $(caller)" | tee -a $LOGFILE 1>&2
}
trap err_report ERR
その後のスクリプトでは次のようになります。
<some command which occasionally will return a non-zero exit code>
if [ $? -eq 0 ]; then
<handle stuff>
fi
コマンドがゼロ以外を返すたびに、トラップがトリガーされます。コードのこの部分だけを回避できますか?
この質問を確認しました:`set -eu` 使用時の EXIT および ERR トラップの動作を修正 しかし、それを自分のケースにどのように適用すればよいのか、あるいは適用できるのか、よくわかりません。
答え1
エラーコードがすぐに「キャッチ」された場合はトリガーERR
trap
されません。つまり、できるuse文などを使用するif
と、エラートラップを常にオン/オフにする必要がなくなります。ただし、できないフロー制御のチェックを使用してください$?
。そのチェックに到達する時点で、キャッチされていないエラーが既に発生している可能性があります。
失敗すると予想されるコマンドがある場合、しないでくださいこれらの失敗によって をトリガーしたい場合はtrap
、失敗をキャッチするだけです。 失敗をステートメントで囲むのはif
面倒で冗長ですが、次の省略形はうまく機能します。
/bin/false || : # will not trigger an ERR trap
ただし、コマンドが失敗したときに何かを実行したい場合は、if
次のようにすれば問題ありません。
if ! /bin/false; then
echo "this was not caught by the trap!"
fi
または、代わりに、else
エラー状態もキャッチします。
if /bin/false; then
: # dead code
else
echo "this was not caught by the trap!"
fi
つまり、即時かつ本質的に説明できないエラー状態がある場合にのみトリップしますset -e
。trap "command" ERR
答え2
ERR
必要に応じて、コードの一部でトラップを有効/無効にすることができます。
#!/bin/bash
err_report() {
echo "errexit on line $(caller)"
}
trap err_report ERR
trap - ERR # disable ERR trap
false
if [ $? -eq 0 ]; then
printf "OK\n"
else
printf "FAIL\n" # prints FAIL
fi
trap err_report ERR # enable ERR trap
false # prints errexit on line 14
答え3
ERR トラップを回避したいが、関数の戻りコードを破棄したくないことがよくあります。そこで、私が使用するパターンは次のとおりです。
RC=0
some_function || RC=$?
それから、RC で必要なことはすべて行います。
答え4
トラップERR
は と同じルールに従いますset -e
。つまり、条件として使用されるコマンドには影響しません。つまり、
trap "echo error" ERR
false # this should trigger the trap
if ! false; then # this shouldn't
echo handle stuff
fi
if
条件内のコマンドはどれでもコマンドの場合は、 である必要はありません[ .. ]
。したがって、コマンドの終了ステータスの true/false 評価のみが必要な場合は、条件で直接 を使用しますif
。
終了コードを保存する必要がある場合そしてこのERR
罠を避けるには、次のようなことをする必要があります
somecmd && :; ret=$?
ここで、 はトラップ&&
を潰しますERR
が、終了コードがゼロの場合にのみ実行されるため、 の後の終了コードは同じであることがわかります:
。
確認したいことがありますBashFAQ 105: set -e (または set -o errexit、または trap ERR) が期待どおりに動作しないのはなぜですか?