怎么做"设置-e"使用子壳?

时间:2014-03-25 09:31:59

标签: bash error-handling return-code

我想知道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退出后失败,但事实并非如此。有人可以解释一下吗?

3 个答案:

答案 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和subshel​​l命令的不同实现,正如another answer所指出的那样。