koj*_*iro 5 bash exit-code bash-trap
trap由于这个问题,我正在玩一个函数内部,并提出了这个次要问题.给出以下代码:
d() {
trap 'return' ERR
false
echo hi
}
Run Code Online (Sandbox Code Playgroud)
如果我运行d,trap导致shell从函数返回而不打印'hi'.到现在为止还挺好.但如果我第二次运行它,我会收到来自shell的消息:
-bash:return:只能从函数或源脚本"返回"
起初,我认为这意味着ERR sig发生了两次:一次当false给出非零退出状态(在函数内部)时,再次当函数本身返回非零退出状态(在函数外部)时.但是这个假设并没有阻止这个测试:
e() {
trap 'echo +;return' ERR
false
echo hi
}
Run Code Online (Sandbox Code Playgroud)
如果我运行上面,无论我怎么经常运行它,我不再让不仅可以return从函数或执行的脚本由bash的警告.为什么shell处理的复合命令与traparg中的简单命令不同?
我的目标是维护导致函数退出的命令的实际退出状态,但我认为导致上述行为的任何因素也会导致捕获退出状态变得复杂:
f() {
trap '
local s=$?
echo $s
return $s' ERR
false
echo hi
}
bash> f; echo $?
1
0
Run Code Online (Sandbox Code Playgroud)
笏?有人可以解释为什么$s在这里扩展到两个不同的值,如果事实证明是相同的原因,上面的区别return和echo +; return?
您的第一个结论是正确的:ERR 信号发生了两次。
\n\n在第一次执行\'d\'期间,您在全局范围内定义了一个陷阱。这会影响接下来的命令(当前对d的调用不受影响)。\n在第二次执行\'d\'期间,你再次定义了一个陷阱(不是很有用),\'false\'的调用失败,所以我们执行陷阱定义的处理程序。然后我们返回到父 shell,\'d\' 也失败了,所以我们再次执行陷阱。
\n\n只是一句话。ERR 可以作为“sigspec”参数给出,但 ERR 不是信号;-) 来自 BASH 手册:
\n\nIf a sigspec is ERR, the command arg is executed whenever a sim\xe2\x80\x90\nple command has a non-zero exit status, subject to the following\nconditions. [...]\nThese are the same conditions obeyed by the errexit option.\nRun Code Online (Sandbox Code Playgroud)\n\n通过函数“e”,ERR 处理程序执行成功的“echo”命令。这就是为什么“e”函数不会失败,这就是为什么在这种情况下 ERR 处理程序不会被调用两次。
\n\n如果你尝试“e; echo $?” 你会读到“0”。
\n\n然后我尝试了你的“f”功能。我观察到了同样的行为(我很惊讶)。原因并不是“ $s”的糟糕扩展。如果您尝试硬编码一个值,您应该观察到当陷阱处理程序执行时,给“return”语句的参数被忽略。
\n\n我不知道这是正常行为还是 BASH 的错误...或者可能是避免解释器中无限循环的技巧:-)
\n\n顺便说一句,我认为这不是一个很好的trap使用方式。我们可以通过创建子 shell 来避免 trap 的副作用。在这种情况下,我们避免父 shell 中的错误,并保留内部函数的退出代码:
\n\ng() (\n trap \'return\' ERR\n false\n echo hi\n)\nRun Code Online (Sandbox Code Playgroud)\n