特定のコマンドがERRトラップをトリガーするのを防ぐ方法は?

特定のコマンドがERRトラップをトリガーするのを防ぐ方法は?

私はBashスクリプトでエラーをキャッチし、発生した内容をログに出力するためにERRトラップを使用しています。 (この質問に似ています:トラップ、ERR、エコーエラーライン)期待通りに動作します。唯一の問題は、私のスクリプトのある時点で終了コード! = 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実行されません。できる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ようになります。どの必ずしもそうではないコマンドです[ .. ]。したがって、コマンドの終了状態の真/偽の評価が必要な場合は、if条件で直接使用できます。

終了コードを保存する必要がある場合そしてトラップを回避するには、ERR次の作業を行う必要があります。

somecmd && :; ret=$?

ここではトラップは&&圧縮されますが、ERR終了コードが0の場合にのみ実行されるため、後続の終了コードが同じであることがわかります:

確認したいかもしれませんBashFAQ 105:-eを設定(または-o errexitまたはトラップERRを設定)しても、期待どおりに機能しないのはなぜですか?

関連情報