陷阱/返回后退出状态在哪里?

时间:2014-05-22 14:24:12

标签: bash exit-code bash-trap

由于this question,我在函数内部使用trap,并提出了这个次要问题。给出以下代码:

d() {
    trap 'return' ERR
    false
    echo hi
}

如果我运行dtrap会导致shell从函数返回而不打印'hi'。到现在为止还挺好。但是,如果我第二次运行它,我会收到来自shell的消息:

  

-bash:return:只能从函数或源脚本“返回”

首先,我认为这意味着ERR sig发生了两次:一次false给出非零退出状态(在函数内),再次当函数本身返回非零退出状态时(函数外部) )。但是这个假设并没有阻碍这个测试:

e() {
    trap 'echo +;return' ERR
    false
    echo hi
}

如果我运行上述操作,无论我多久运行一次,我都不再从bash的函数或源脚本警告中获取只能return。为什么shell处理的复合命令与trap arg中的简单命令不同?

我的目标是维护导致函数退出的命令的实际退出状态,但我认为导致上述行为的任何因素也会导致捕获退出状态变得复杂:

f() {
    trap '
        local s=$?
        echo $s
        return $s' ERR
    false
    echo hi
}

bash> f; echo $?
1
0

笏?有人可以解释为什么$s在这里扩展到两个不同的值,如果结果是相同的原因,那么returnecho +; return之间的上述区别?

1 个答案:

答案 0 :(得分:3)

你的第一个结论是正确的:ERR sig发生了两次。

在第一次执行'd'期间,您可以全局定义陷阱。这会影响下一个命令(d的当前调用不受影响)。 在第二次执行'd'期间,再次定义一个陷阱(不是很有用),'false'的调用失败,所以我们执行陷阱定义的处理程序。然后我们返回父shell,其中'd'也失败了,所以我们再次执行陷阱。

只是一个评论。 ERR可以作为'sigspec'参数给出,但ERR不是信号;-)来自BASH的手册:

If a sigspec is ERR, the command arg is executed whenever a sim‐
ple command has a non-zero exit status, subject to the following
conditions. [...]
These are  the  same  conditions obeyed by the errexit option.

使用函数'e',ERR处理程序执行成功的'echo'命令。这就是'e'函数不会失败的原因,这就是为什么在这种情况下ERR处理程序不会被调用两次。

如果您尝试“e; echo $?”你会读到“0”。

然后我尝试了你的'f'功能。我观察到了同样的行为(我很惊讶)。原因是“$ s”的错误消费。如果您尝试对某个值进行硬编码,那么您应该观察到,当由陷阱处理程序执行时,忽略给予'return'语句的参数。

我不知道这是正常行为还是BASH的错误...或者可能是避免解释器无限循环的技巧: - )

顺便说一句,在我看来,它并不是很好用的陷阱。我们可以通过创建子shell来避免陷阱的副作用。在这种情况下,我们避免了父shell中的错误,并保留了内部函数的exitcode:

g() (
    trap 'return' ERR
    false
    echo hi
)