我在命令行中使用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
有趣的是,如果我在子shell后删除&&
和||
部分,那么(...)
也会表现良好。
代码3:
( set -e; echo "$BASHPID: start"; false; echo "foobar"; date; )
5940: start
我得到的结论是:
(...)
的行为与bash -c
(...) && false
与(...)
的行为不同,也会更改子shell的行为。我在解释这种奇怪的(至少对我而言)行为时犯了一些明显的错误吗?
答案 0 :(得分:2)
set -e
与&&
的行为是故意的。
当命令是&&
序列的一部分时,它明确地不会触发。
来自POSIX规范:
<强> -e 强>
当此选项打开时,当任何命令失败时(由于Shell错误的后果中列出的任何原因或返回大于零的退出状态),shell将立即退出,但出现以下异常: 多命令管道中任何单个命令的失败都不会导致shell退出。只考虑管道本身的故障。
在执行while,until,if或elif保留字之后的复合列表时,应忽略-e设置,以!开头的管道!保留字,或除最后一个之外的AND-OR列表的任何命令。
如果在忽略-e时,除了subshell命令之外的复合命令的退出状态是失败的结果,则-e不应用于此命令。
此要求分别适用于shell环境和每个子shell环境。例如,在:
set -e; (false; echo one) | cat; echo two
false命令导致子shell退出而不执行echo one;但是,echo 2是因为管道的退出状态(false; echo one)执行的猫是零。
我认为这里的区别在于shell是否知道这一事实。
(...)
大概是因为当前shell执行它而bash -c
可能不会因为它是一个完全外部的过程(或其他东西)。
最后一点是猜测,在我看来,这里的子shell行为完全没有用,使得set -e
不可靠(这就是许多人建议避免它的原因)。
虽然看起来这可能也提供了一种逃生舱口&#34;对于那个可靠性问题,如果显式运行的shell没有脚本组合的问题。