带有 `set -e` 的 Bash 脚本不会在 `... && ...` 命令上停止

带有 `set -e` 的 Bash 脚本不会在 `... && ...` 命令上停止

set -e习惯于第一次出现错误时停止 bash 脚本

一切正常,除非我使用以下命令&&

$ cat script
set -e
cd not_existing_dir && echo 123
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
I'm running! =P
$

和....相比:

$ cat script
set -e
cd not_existing_dir
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
$

第一个示例仍然会回显I'm running!,但第二个示例不会。为什么他们的行为不同?

UPD。类似问题:https://stackoverflow.com/questions/6930295/set-e-and-short-tests

答案1

这是有记录的行为。这bash(1) 手册页说,对于set -e,

while如果失败的命令是紧跟在or关键字之后的命令列表的一部分,是紧跟在或保留字 until之后的测试的一部分,则 shell 不会退出,ifelif&&||列表中执行的任何命令的一部分&&除了最后一个或 之后的命令||,管道中除最后一个命令之外的任何命令,或者命令的返回值与!.
[强调。]

还有POSIX外壳命令语言规格 确认这是正确的行为:

执行、、或保留字-e后的复合列表,以保留字开头的管道,或除最后一个之外的任何 AND-OR 列表的命令时,应忽略该设置。whileuntilifelif!

第2.9.3节列表该文件的定义

&&AND-OR 列表是由运算符“ ”和“ ”分隔的一个或多个管道的序列||

答案2

set -e选项在某些情况下不起作用,这是标准行为,并且可以跨 POSIX 兼容 shell 移植。


失败的命令是管道的一部分:

false | true; echo printed

将打印printed.

并且只考虑管道本身的故障:

true | false; echo 'not printed'

不会打印任何内容。


失败的命令在whileuntilifelif保留字之后的复合列表中运行,以保留字开头的管道,或者作为除最后一个之外的!一部分&&或列表的任何命令:||

false || true; echo printed

最后一个命令失败仍然会受影响set -e

true && false; echo 'not printed'

子外壳复合命令失败:

(false; echo 'not printed') | cat -; echo printed

答案3

我的猜测是 if-then 条件作为一个整体评估为 true。

我试过

set -e
if cd not_existing_dir
then  echo 123
fi
echo "I'm running! =P"

谁给

-bash: cd: not_existing_dir: No such file or directory
I'm running! =P

错误代码被 if 条件捕获,因此 bash 不会触发执行结束。

相关内容