我在这里有点困惑。我的目标是当脚本中的任何命令失败时,让 bash 脚本以非零退出代码退出。使用 -e 标志,我认为情况会如此,即使在使用子外壳时也是如此。下面是一个简化的例子:
#!/bin/bash -e
(false)
echo $?
echo "Line reached!"
这是运行时的输出:
[$]>Tests/Exec/continuous-integration.sh
1
Line reached!
Bash 版本:CentOS 上的 3.2.25
我在这里有点困惑。我的目标是当脚本中的任何命令失败时,让 bash 脚本以非零退出代码退出。使用 -e 标志,我认为情况会如此,即使在使用子外壳时也是如此。下面是一个简化的例子:
#!/bin/bash -e
(false)
echo $?
echo "Line reached!"
这是运行时的输出:
[$]>Tests/Exec/continuous-integration.sh
1
Line reached!
Bash 版本:CentOS 上的 3.2.25
似乎这与您的bash
. 在我可以访问的机器上,bash 版本 3.1.17 和 3.2.39 会表现出这种行为,而 bash 4.1.5 则不会。
虽然有点难看,但适用于两个版本的解决方案可能是这样的:
#!/bin/bash -e
(false) || exit $?
echo $?
echo "Line reached!"
bash 源代码更改日志中有一些与set -e
选项错误相关的注释。
我在 El Capitan 之前的 SuSE 11.3 和 Mac OS 上的 bash 版本 3.2.51 中看到了这种行为。El Capitan 上的 Bash 3.2.57 具有“正确”的行为,即像 bash 4。
但是,上面提出的解决方法是添加“|| exit $?” 在 subshell 的结束括号之后,无论什么版本的 bash,都会破坏 -e 标志的意图。来自 man bash:
-e 如果简单命令(参见上面的 SHELL GRAMMAR)以非零状态退出,则立即退出。如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、if 语句中测试的一部分、&& 或 || 的一部分,则 shell 不会退出 列表, ...
一个子shell,后跟“|| exit $?” 显然算作命令列表;并且 bash -e 标志将不适用于子外壳内的任何命令。尝试一下:
$ 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,因为那个“回声”跑了。所以“||退出$?” 甚至不会运行“退出”。可能不是我们想要的!
据我所知,以下公式与 bash 版本兼容,无论它们是否在 subshell 之后尊重 bash -e 。如果碰巧重置了 -e 标志,它甚至会正常运行:
在 bash 脚本中每个子 shell 的右括号之后立即添加以下行:
case $?/$- in ( 0/* ) ;; ( */*e* ) exit $? ;; esac # honor bash -e flag when subshell returns