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


14

我使用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


您希望第一个示例发生什么?
2016年

@Flup我希望脚本在cd命令执行失败后会停止运行
907th

1
有关行为令人惊讶的地方的一般性讨论,请参见BashFAQ#105set -e
查尔斯·达菲,2016年

Answers:


10

这是记录的行为。该庆典(1)手册页说,对set -e

如果失败的命令是紧接在whileuntil关键字之后的命令列表的一部分,紧跟在ifelif保留字 之后的测试的一部分,在&&||列表中执行的任何命令的一部分, 除final &&或之后的命令之外的||外壳程序,则外壳程序不会退出,管道中的命令,但最后一个管道,或者命令的返回值被反转!
[重点已添加。]

并且POSIX Shell命令语言规范 确认这是正确的行为:

-e设置应执行以下化合物列表时被忽略whileuntilif,或elif保留字,管道期初!保留字,或小于最后的其他与或列表的任何命令。

以及该文件的第2.9.3节清单定义

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


9

set -e选项在某些情况下不起作用,这是标准行为,可在POSIX兼容外壳程序中移植。


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

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

谢谢!使用echo "printed"echo "not_printed"在您的示例中(而不是echo 1)会更清楚。
907th

3
请注意,尽管YMMV使用不同的外壳,甚至同一外壳的不同版本,set -e都会在中(false && true); echo not here(而不是在)中导致退出{ false && true; }; echo here。我不会碰set -e驳竿,而是会进行适当的错误处理。
斯特凡Chazelas

1

我的猜测是如果-那么整个条件评估为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不会触发执行结束。


但我不使用if ... fi
907th

我知道,这是一个隐含的if。
Archemar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.