使用 (...) 创建的子壳的行为与 bash -c '...' 不同



我在命令行的(...)中使用set -e,但在执行false命令时,它不会退出子shell。

代码1:

( set -e; echo "$BASHPID: start"; false; echo "foobar"; date; ) && 
echo "$BASHPID: ok" || echo "$BASHPID: nope"
9136: start
foobar
Wed, Apr 29, 2015  7:14:24 PM
7292: ok

但是,如果我使用bash -c创建子shell,那么它的行为与我预期的一样。

代码2:

bash -c 'set -e; echo "$BASHPID: start"; false; echo "foobar"; date;' &&
echo "$BASHPID: ok" || echo "$BASHPID: nope"
7880: start
7292: nope

有趣的是,如果我在子壳之后去除&&||部分,那么(...)也表现良好。

代码3:

( set -e; echo "$BASHPID: start"; false; echo "foobar"; date; )
5940: start

所以我得到的结论是:

  1. (...)的行为与bash -c不同
  2. CCD_ 10的行为与CCD_ 11不同

我在解释这种奇怪的(至少对我来说)行为时是否犯了一些明显的错误?

set -e&&的行为是有意的。

当命令是&&序列的一部分时,它明确不触发。

来自POSIX规范:

-e

如果此选项处于启用状态,则当任何命令失败时(由于"Shell错误的后果"中列出的任何原因或返回大于零的退出状态),Shell应立即退出,但以下情况除外:多命令管道中任何单个命令的失败都不应导致外壳退出。只应考虑管道本身的故障。

执行while后面的复合列表时,应忽略-e设置,直到if或elif保留字出现以!开头的管道为止!保留字或除最后一个之外的"与或"列表的任何命令。

如果子shell命令以外的复合命令的退出状态是由于-e被忽略时出现故障而导致的,则-e不应适用于此命令。

此要求分别适用于shell环境和每个子shell环境。例如,在:中

set -e; (false; echo one) | cat; echo two

false命令导致子shell退出而不执行echo-one;但是,由于管道的退出状态(false;echo-one)|cat为零,所以执行echo-two。

我假设这里的区别在于shell是否知道这个事实。

(...)可能会执行,因为当前shell执行它,而bash -c可能不会,因为这是一个完全外部的进程(或其他什么)。

最后一点是猜测,在我看来,这里的子外壳行为完全没有帮助,并使set -e不可靠(这就是为什么许多人建议避免它)。

尽管如果显式运行的shell在脚本的组成方面没有这个问题,那么这似乎也可能为可靠性问题提供一种"逃生通道"。

相关内容

  • 没有找到相关文章

最新更新