Bash “怎么做?”;集合-e";使用子shell?

Bash “怎么做?”;集合-e";使用子shell?,bash,error-handling,return-code,Bash,Error Handling,Return Code,我想知道set-e是否通过子shell传播(即子shell是否继承其父级的-e设置),因此我做了一些实验。我发现了一些我无法解释的奇怪结果 首先,这里是一些基本测试。他们回报了我所期望的 ( true; false ) # 1 ( false; true ) # 0 ( set -e; false; true ) # 1 现在我尝试了如果我在我的子shell中放置子shell会发生什么。此表达式返回1,表示它正在传播 ( set -e; ( false; tru

我想知道
set-e
是否通过子shell传播(即子shell是否继承其父级的
-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 )

为什么??在这两种情况下,无论
set-e
是否传播,内部子shell都返回1(正如我在开头检查的那样)。外部子shell有
set-e
,这意味着内部子shell退出后它应该失败,但它没有。有人能解释一下吗?

来自
man bash

设置[+abefhkmnptuvxBCEHPT][+o选项名称][arg…]

-e

如果管道(可能由单个简单 命令),括在括号中的子shell命令,或 作为大括号括起的命令列表的一部分执行的命令(请参见 SHELL语法(如上所述)以非零状态退出。贝壳有 如果失败的命令是命令列表的一部分,则不退出 紧跟在while或until关键字之后,是测试的一部分 在if或elif保留字之后,执行任何命令的一部分 在&&或| |列表中,除了最后的&&或| |后面的命令之外, 管道中的任何命令,但最后一个命令除外,或者如果该命令返回 值正在用!反转!。如果设置了错误,则执行错误陷阱 在外壳退出之前。此选项适用于外壳 环境和每个子shell环境(请参见命令 执行环境),并可能导致子shell在 执行子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

bash
4之前,
set-e
仅在一个简单命令具有非零退出时才导致shell退出(强调):

-e如果简单命令以非零状态退出(请参见上面的SHELL语法),则立即退出

bash
4(可能是4.1,我没有要检查的4.0)中,
-e
的效果扩展到更复杂的命令:

-如果一个管道(可能由一个简单命令组成)、一个子shell com- 括在括号中的命令,或作为括在括号中的命令列表的一部分执行的命令之一 按大括号(参见上面的SHELL语法)以非零状态退出


从bash4.4开始,这些命令都返回
1

( set -e; ( false; true ) )
( set -e; ( true; false ); true )
( set -e; ( set -e; false; true ); true )

因此,我认为您可能正在使用较旧版本的Bash,它对
set-e
和子shell命令有不同的实现,正如。

所指出的,我可以看到特定的子shell存在,但外部的子shell不存在,但从文档中看不出它应该这样工作。但是它似乎是这样工作的,所以我不得不这样计划我的脚本。嗯,我不知道我是否理解你。在内部子shell中,参数被复制->
(设置-e;(true;false;echo 22);echo 55)
既不打印22也不打印55。在
bash
3.2中,55被回显。在
bash
4.1中,它不是。这可能是由于
bash
4或4.1中的错误修复造成的,尽管我在
bash
发行说明中找不到任何相关内容。
-e
选项的措辞在3.2和4之间发生了变化。在3.2中,它似乎只适用于简单命令,而不适用于复合命令(如子shell)或管道等。它甚至更复杂:如果直接(使用表达式本身的条件,而不是
$?
)测试子shell的返回代码,则会影响子shell的行为。它(bash3)无法摆脱困境<代码>(设置为-e;错误;内部回声);[$?-eq 0]| echo outer打印
outer
(set-e;false;echo inner)| echo outer
打印
inner
。做得很好;从bash 4.3.30开始,措辞是:“如果管道(可能由单个简单命令)、列表或复合命令(参见上面的SHELL语法)以非零状态退出,则立即退出。”