1 つのコマンドが ERR トラップをトリガーするのを防ぐにはどうすればよいですか?

1 つのコマンドが ERR トラップをトリガーするのを防ぐにはどうすればよいですか?

私は、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 -etrap "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) が期待どおりに動作しないのはなぜですか?

関連情報