我想知道set -e
是否通过子壳传播(即子壳是否继承了其父级的-e
设置),所以我做了一些实验。我发现了一些我无法解释的奇怪结果。
首先,这是一些基本测试。他们回归了我的期望。
( true; false ) # 1
( false; true ) # 0
( set -e; false; true ) # 1
现在我尝试了如果我在子shell中放置一个子shell会发生什么。此表达式返回1,表示它传播。
( set -e; ( false; true ) )
然后我尝试了这些表达方式。我希望他们返回1,但我发现他们返回0。
( set -e; ( true; false ); true )
( set -e; ( set -e; false; true ); true )
为什么呢?在这两种情况下,内部子shell返回1,无论set -e
是否传播(我在开头检查)。外部子shell具有set -e
,这意味着它应该在内部子shell退出后失败,但事实并非如此。有人可以解释一下吗?
答案 0 :(得分:11)
在bash
4之前,set -e
似乎只会导致shell退出,如果一个简单的命令具有非零退出(强调我的):
-e如果简单命令(参见上面的SHELL GRAMMAR)以非零状态退出,则立即退出。
在bash
4(可能是4.1,我没有4.0要检查)中,-e
的效果扩展到更复杂的命令:
-e如果一个管道(可能由一个简单的命令组成),一个子shell com-立即退出 括在括号中的命令,或作为命令列表的一部分执行的命令之一 通过大括号(参见上面的SHELL GRAMMAR)以非零状态退出。
答案 1 :(得分:3)
来自man bash
:
设置[+ abefhkmnptuvxBCEHPT] [+ o选项名称] [arg ...]
<强> -e 强>
如果管道(可能包含一个简单的管道)立即退出 命令),括在括号中的子shell命令,或其中一个 作为由大括号括起的命令列表的一部分执行的命令(参见 上面的SHELL GRAMMAR)以非零状态退出。外壳确实如此 如果失败的命令是命令列表的一部分,则不退出 紧接着一段时间或直到关键字,测试的一部分 跟随if或elif保留字,执行任何命令的一部分 在&amp;&amp;或||列表除了最后一个&amp;&amp;之后的命令或||, 管道中的任何命令,但是最后一个,或者命令返回 价值正在被反转! ERR上的陷阱(如果已设置)将被执行 在shell退出之前。此选项适用于shell 环境和每个子shell环境分开(参见COMMAND 上面的执行环境),可能导致子壳退出之前 执行子shell中的所有命令。
因此,当找到false
时,它将退出子shell。
参见几个例子:
# when `false`, exit. Hence, no `echo ho`
$ ( set -e; echo hi; false; echo ho ) ; echo $?
hi
1
# when `false`, exit. Hence, no `echo hu`
$ ( set -e; echo hi; true; echo ho; false; echo hu ) ; echo $?
hi
ho
1
答案 2 :(得分:2)
从Bash 4.4开始,这些命令都返回1
:
( set -e; ( false; true ) )
( set -e; ( true; false ); true )
( set -e; ( set -e; false; true ); true )
所以我认为你可能正在使用旧版本的Bash,它有set -e
和subshell命令的不同实现,正如another answer所指出的那样。