Posix Shell 设置 -e 时测试非零退出代码脚本终止

Posix Shell test non zero exit code script termination when set -e

阅读testshell命令的手册:

man test

描述状态:

Exit with the status determined by EXPRESSION.

但这与我的 POSIX sh 测试脚本示例冲突,我在其中使用 set -eu 如果命令的退出状态不为零,则应终止脚本:

#!/bin/sh

set -eu

status=1
test "$status" -ne 0 && echo "Status not eq 0"
echo "(A) Exit code for "$status" = $?"

echo ""

status=0
test "$status" -ne 0 && echo "Status not eq 0"
echo "(B) Exit code for "$status" = $?"

echo ""

status=1
test "$status" -ne 0
echo "(C) Exit code for "$status" = $?"

echo ""

status=0
test "$status" -ne 0
echo "(D) Exit code for "$status" = $?"

运行宁该脚本提供输出:

Status not eq 0
(A) Exit code for 1 = 0

(B) Exit code for 0 = 1

(C) Exit code for 1 = 0

这就是我对执行流程的理解:

status=1
test "$status" -ne 0 && echo "Status not eq 0"
echo "(A) Exit code for "$status" = $?"

输出:

Status not eq 0
(A) Exit code for 1 = 0

test "$status" -ne 0 的计算结果为真,因此它的退出代码为零,因此执行布尔值 && 之后的表达式,因为它只是一个 echo,它也 returns退出代码为零,因此脚本不会中断并回显下一行 (A) Exit code for 1 = 0

但是对于

status=0
test "$status" -ne 0 && echo "Status not eq 0"
echo "(B) Exit code for "$status" = $?"

输出:

(B) Exit code for 0 = 1

根据前面的推理,test 应该 return 非零,因此不应执行 && 之后的表达式(事实并非如此),但脚本甚至会执行 test returned 非零退出代码 (B) 0 = 1.

的退出代码

为什么脚本会继续执行?由于非零退出状态,它应该制动。

案例没有输出:

status=0
test "$status" -ne 0
echo "(D) Exit code for "$status" = $?"

这对我来说表明脚本执行在行 test "$status" -ne 0 处终止,如果你 运行 echo $? 在 运行 脚本之后你实际上会得到1.

但是当测试 returns 示例的非零退出状态 (D) 但它不是示例 (B)?

(D)(B)的唯一区别是(B) 在测试后有 && echo "Status not eq 0" 但未执行并且退出状态为 1 所以在 (B) 的情况下脚本应该终止但它没有't 如果测试的退出状态以某种方式如此特殊地处理,因此它不会终止具有 set -e 的脚本,那么为什么它会终止 (D) 示例的脚本?

编辑

类似于 test 的行为 ls

对于脚本:

#!/bin/sh

set -eu

ls notexitingfile && echo "File exists"
echo "Exit code for ls = $?"

ls notexitingfile
echo "Exit code for ls = $?"

输出为:

ls: cannot access 'notexitingfile': No such file or directory
Exit code for ls = 2
ls: cannot access 'notexitingfile': No such file or directory

注意第一个例子 Exit code for ls = 2,第二个例子没有。

我认为意外行为的原因可能是我对脚本终止的误解 (set -e) 由于使用 && 运算符时非零退出代码。

set -e 选项仅适用于单个命令。 它不适用于与 || 组合的命令或 &&.

男人 bash 说:

如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、紧跟在 if 或 elif 保留字之后的测试的一部分、执行的任何命令的一部分,则 shell 不会退出在 && 或 || 中列出除最后一个 && 或 || 之后的命令之外的列表,管道中除最后一个命令之外的任何命令,或者如果命令的 return 值被 !.

反转