子shell失败时为什么不用bash标志-e exit?

时间:2013-02-20 01:15:50

标签: bash

我在这里有点困惑。我的目标是当脚本中的任何命令失败时,使用非零退出代码退出bash脚本。使用-e标志,我认为即使使用子shell也是如此。以下是一个简化示例:

#!/bin/bash -e

(false)

echo $?
echo "Line reached!"

以下是run:

时的输出
[$]>Tests/Exec/continuous-integration.sh 
1
Line reached!

Bash版本:CentOS上的3.2.25

2 个答案:

答案 0 :(得分:10)

好像这与您的bash版本有关。在我有权访问的计算机上,bash版本3.1.17和3.2.39表现出这种行为,bash 4.1.5没有。

虽然有点难看,但在两个版本中都有效的解决方案可能是这样的:

#!/bin/bash -e

(false) || exit $?

echo $?
echo "Line reached!"

bash源更改日志中有一些注释与set -e选项的错误相关。

答案 1 :(得分:0)

我在El Capitan之前的SuSE 11.3和Mac OS上都看到了bash版本3.2.51中的这种行为。关于El Capitan的Bash 3.2.57有正确的#34;行为,即像bash 4。

但是,上面提出的解决方法,添加" ||退出$?"在子shell的关闭之后,无论什么版本的bash,都会击败-e标志的意图。来自man bash:

  

-e如果出现一个简单的命令(参见上面的SHELL GRAMMAR),则立即退出   具有非零状态。如果失败的命令是shell,则shell不会退出   部分命令列表紧跟一段时间或直到关键字,部分   if语句中的测试,&&和或||列表,......

子shell后跟" ||退出$?"显然算作一个命令清单;并且bash -e标志不适用于子shell内的任何命令。试试吧:

$ set -e
$ ( echo before the error; false; echo after the error, status $?; ) || echo after the subshell, status $?
before the error
after the error, status 1
$

因为子shell后跟||,所以"在错误后回显"即使使用set -e也可以运行。不仅如此,子shell退出0,因为" echo"跑了。所以" ||退出$?"甚至不会运行"退出"。可能不是我们想要的!

据我所知,以下公式与bash版本兼容,无论他们是否尊重bash -e在子shell之后。如果-e标志恰好被重置,它甚至可以正常运行:

  

在bash脚本中每个子shell的右括号后立即添加以下行:

case $?/$- in ( 0/* ) ;; ( */*e* ) exit $? ;; esac # honor bash -e flag when subshell returns