注意:如果您正在寻找解决方法,因为set -e在函数中不起作用,请转到“set -e” in a function。这个问题是关于为什么它没有按预期工作。
当在GNU bash上运行以下版本时,版本4.1.5(1)-release:
set -ex
PS4=' ${FUNCNAME[0]}: $LINENO: '
function f() {
set -e
false
echo $@
}
! f why does it display ? It should stop because of -e
f
显示
: 11: f why does it display '?' It should stop because of -e
f: 6: set -e
f: 7: false
f: 8: echo why does it display '?' It should stop because of -e
why does it display ? It should stop because of -e
: 12: f
f: 6: set -e
f: 7: false
我希望它永远不会超过false,因为-e
表示“当命令具有非零退出状态时退出”。我知道-e
有一个棘手的行为,如http://mywiki.wooledge.org/BashFAQ/105中所述,但我想了解在这个特定情况下会发生什么。我正在使用-e
,它在许多非常简单的场景中证明是最有用的。这种情况有点棘手,但如果可以解释,我可以使用-e
代替每行后添加|| exit 1
。
答案 0 :(得分:5)
在尝试解决类似问题时,我为set -e
阅读了man page:
-e
errexit
如果一个简单的命令退出非零,则立即退出 状态,除非失败的命令是until或的一部分 while循环,if语句的一部分,
&&
或||
列表的一部分, 或者如果使用!
反转命令的返回状态。
注意关于返回状态被倒置的最后一位。我想函数f
的逻辑否定必然会影响该函数中set -e
的行为。
答案 1 :(得分:2)
以下是trap
的{{1}}部分(我的重点):
如果sigspec是ERR,则只要简单命令具有非零退出状态,就会执行命令arg,具体取决于以下条件。 如果失败的命令是紧跟在while或until关键字之后的命令列表的一部分,if语句中的部分测试,在&&中执行的命令的一部分,则不执行ERR陷阱;或||列表,或者如果命令的返回值被反转!这些是errexit选项遵循的相同条件。
所以man bash
有效地禁用! command
内的ERR
trap
。我猜想,如果你在使用command
运行退出代码后“明确地”检查退出代码,那么可能不希望命令提前退出。看起来很糟糕的设计,因为它可以用来在任何地方有效地禁用安全措施。
答案 2 :(得分:1)
我无法准确回答为什么,但我找到了这个代码段here:
在一个稍微相关的说明中,默认情况下,bash会获取管道中最后一项的错误状态,这可能不是您想要的。例如,false | true将被视为已成功。如果您希望失败,那么您可以使用set -o pipefail使其失败。
通过更新您的脚本:
function f() {
echo $SHELLOPTS
set -e
set -o pipefail
false
echo "$@"
}
它似乎表现得像你期望的那样。
因此,我对“为什么”(可能与你现在相同)的最佳猜测是!
导致函数以某种“管道”模式处理。再次......为什么!
意味着“管道”,我想我真的不知道。也许一个更好的bash专家可以为我们回答这个部分。