为什么测试“$?”查看命令是否成功,反模式?
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 -e
或 ERR
陷阱的目的考虑非零退出状态。
因此:
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
我看到 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 -e
或 ERR
陷阱的目的考虑非零退出状态。
因此:
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