为什么测试“$?”查看命令是否成功,反模式?

Why is testing "$?" to see if a command succeeded or not, an anti-pattern?

我看到 here 测试是否 $?为零(成功)或其他(失败)是一种反模式,但我无法在其他任何地方找到它。

坚持Wikipedia的反模式定义:"An anti-pattern (or anti-pattern) is a common response to a recurring problem that is usually ineffective and risks being highly counterproductive."为什么这是反模式?

这是一种反模式,因为它引入了复杂性,如果您根本不需要记录退出状态,这种复杂性就不会存在。

if your_command; then ...

更容易出错
your_command
if [ "$?" -eq 0 ]; then ...

有关可能出错的示例:考虑 traps,甚至为调试添加新的 echo 语句,修改 $?。对于 reader 来说,在不改变逻辑流程的情况下,单独的行 运行 your_command 不能在其下方添加任何内容。

即:

your_command
echo "Finished running your_command" >&2
if [ "$?" -eq 0 ]; then ...

...正在检查 echo,而不是实际命令。


因此,如果您确实 需要以比立即分支其值是否为零更细化的方式处理退出状态,您应该在同一行:

# whitelisting a nonzero value for an example of when "if your_command" won't do.
your_command; your_command_retval=$?
echo "Finished running your_command" >&2 ## now, adding more logging won't break the logic.
case $your_command_retval in
  0|2) echo "your_command exited in an acceptable way" >&2;;
  *)   echo "your_command exited in an unacceptable way" >&2;;
esac

最后:如果您将 your_command 包含在 if 语句中,这会将其标记为 tested,这样您的 shell 就赢了出于 set -eERR 陷阱的目的考虑非零退出状态。

因此:

set -e
your_command
if [ "$?" -eq 0 ]; then ...

...永远不会 (除了一些困扰 set -e 行为的极端情况和警告) 以任何方式达到 if 声明$? 的值不同于 0,因为在这种情况下 set -e 将强制退出。相比之下:

set -e
if your_command; then ...

...将 your_command 的退出状态标记为已测试,因此不认为它会导致根据 set -e.

强制脚本退出

在我看来,如果您不需要 return 命令的值而只需要检查状态,那么这是一种反模式。

如果我们需要函数 return 值和退出代码,则没有其他方法(或者我不知道,如果我错了请纠正我)。在下面的示例中,仅当先前的命令成功并且我们在其他函数中使用 return 值

时,我们才需要继续

示例:

test() { echo "A" ; return 1; }
l_value=$(test); l_exit_code=$?;

if (( l_exit_code == 0 )); then
   fn_other_function_to_pass_value $l_value
else
   echo "ERROR" >&2
   exit 1
fi