如何防止某个命令触发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)没有达到我的预期?

相关内容