我正在使用 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)没有达到我的预期?