
我正在使用 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)沒有達到我的預期?