如何防止某個指令觸發ERR trap?

如何防止某個指令觸發ERR trap?

我正在使用 ERR 陷阱來捕獲 bash 腳本中的任何錯誤並輸出日誌中發生的情況。 (類似這個問題:Trap、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觸發,這表示您使用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陷阱,但由於它僅在退出代碼為零時運行,因此我們將知道 後的退出代碼是相同的:

您可能想檢查BashFAQ 105:為什麼 set -e (或 set -o errexit 或 trap ERR)沒有達到我的預期?

相關內容