set -e 不尊重逻辑非

set -e does not respect logical not

在几个 shell 秒后,逻辑非 (!) 将 "invert" 程序的 return 代码。

然而,在带有 set -e 的 shell 脚本中,逻辑 not 似乎导致程序实际上永远不会失败。为什么是这样?

bashzshksh 中进行了测试,结果相同。

$ cat test.sh 
set -ex

# setup
touch myfile

# observe available files
ls .

# succeeds
ls myfile; echo $?

# this succeeds as expected
! ls notafile; echo $?

# why does this not exit when the return code is clearly non-zero?
! ls myfile; echo $?

# this exits as expected when there is a non-zero return code
ls notafile; echo $?

# becasue we exit just above, this never get executed
echo "test passed"

结果:

bash test.sh 
+ touch myfile
+ ls .
myfile  test.sh
+ ls myfile
myfile
+ echo 0
0
+ ls notafile
ls: cannot access 'notafile': No such file or directory
+ echo 0
0
+ ls myfile
myfile
+ echo 1
1
+ ls notafile
ls: cannot access 'notafile': No such file or directory

这是指定的行为。来自 Bash Manual

The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !.

这也是specified by POSIX(斜体是我的):

The -e setting shall be ignored when executing the compound list following the while, until, if, or elif reserved word, a pipeline beginning with the ! reserved word, or any command of an AND-OR list other than the last.