在 if
语句中检查 exit status 以回显特定输出的最佳方法是什么?
我认为它是:
if [ $? -eq 1 ]
then
echo "blah blah blah"
fi
我还遇到的问题是 exit
语句位于 if
语句之前,因为它必须具有该退出代码。另外,我知道我做错了什么,因为 exit 显然会退出程序。
some_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}
每个运行的命令都有一个退出状态。
该检查正在查看在该行运行之前最近完成的命令的退出状态。
如果您希望 您的 脚本在该测试返回 true(前一个命令失败)时退出,那么您将 exit 1
(或其他)放在 echo
之后的 if
块内。
话虽如此,如果您正在运行该命令并想要测试其输出,则使用以下命令通常更直接。
if some_command; then
echo command returned true
else
echo command returned some error
fi
或者使用 !
来扭转这种情况
if ! some_command; then
echo command returned some error
else
echo command returned true
fi
请注意,尽管这些都不关心错误代码是什么。如果您知道您只关心特定的错误代码,那么您需要手动检查 $?
。
请注意,退出代码 != 0 用于报告错误。所以,最好这样做:
retVal=$?
if [ $retVal -ne 0 ]; then
echo "Error"
fi
exit $retVal
代替
# will fail for error codes == 1
retVal=$?
if [ $retVal -eq 1 ]; then
echo "Error"
fi
exit $retVal
dnf
开发者选择了这种方式,那是他们的选择。但是,他们的选择并没有破坏规范:)
# will fail for error codes > 1
但 $retVal -eq 1
检查错误代码是否等于 1?
显式 if
语句的替代方法
最低限度:
test $? -eq 0 || echo "something bad happened"
完全的:
EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened";
exit $EXITCODE
$?
是一个与其他参数一样的参数。您可以在最终调用 exit
之前保存它的值以供使用。
exit_status=$?
if [ $exit_status -eq 1 ]; then
echo "blah blah blah"
fi
exit $exit_status
作为记录,如果脚本使用 set -e
(或 #!/bin/bash -e
)运行,因此您不能直接检查 $?
(因为脚本将在除零之外的任何返回代码处终止),但想要处理特定代码, @gboffis comment 很棒:
/some/command || error_code=$?
if [ "${error_code}" -eq 2 ]; then
...
/some/command
在 PATH 中,这不会中断吗? error_code
未设置。
/bin/mkdir
,它应该返回 1。您确定您尝试的命令返回的退出代码不是 0 吗?例如,在不存在的文件上的 /usr/bin/file
会打印错误但仍返回 0 🤷
|| is_fail=true; if [ "$is_fail" = true ]; then . . .
只是添加到有用且详细的 answer 中:
如果您必须明确检查退出代码,最好使用算术运算符 (( ... ))
,这样:
run_some_command
(($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }
或者,使用 case
语句:
run_some_command; ec=$? # grab the exit code into a variable so that it can
# be reused later, without the fear of being overwritten
case $ec in
0) ;;
1) printf '%s\n' "Command exited with non-zero"; exit 1;;
*) do_something_else;;
esac
关于 Bash 中的错误处理的相关答案:
在 Bash 脚本中引发错误
(( $? != 0 ))
还是 [[ $? -ne 0 ]]
,您都不能在这样的布尔检查中使用 $?
,因为它不会像普通变量 (related description) 那样被解析。
(( $retVal )) && echo 'ERROR'
而不是 (( $retVal != 0 ))
或 [[ $retVal -ne 0 ]]
,但这并不一定意味着它更好。事实上,我喜欢使用的快捷方式会让那些不太了解 Bash 的人感到困惑。
如果你正在编写一个函数——这总是首选——你可以像这样传播错误:
function()
{
if <command>; then
echo worked
else
return
fi
}
现在,调用者可以按预期执行 function && next
之类的操作!如果您在 if
块等中有很多事情要做,这很有用(否则只有单行)。可以使用 false
命令轻松测试它。
使用 Z shell (zsh
),您可以简单地使用:
if [[ $(false)? -eq 1 ]]; then echo "yes" ;fi
使用 Bash 且 set -e
已打开时,您可以使用:
false || exit_code=$?
if [[ ${exit_code} -ne 0 ]]; then echo ${exit_code}; fi
这可能仅在一组有限的用例中有用,当我需要捕获命令的输出并将其写入日志文件时,如果退出代码报告出现问题,我会特别使用它。
RESULT=$(my_command_that_might_fail)
if (exit $?)
then
echo "everything went fine."
else
echo "ERROR: $RESULT" >> my_logfile.txt
fi
a_command || return 1
return
仅适用于函数和源脚本。对于另一种情况,您需要exit
(它在函数和源脚本中做的太多)。但是,是的,如果您不需要任何特定的清理或额外的输出,那肯定是一种合理的模式。dash
是许多现代 Linux 发行版中默认的非交互式 shell,它不关心执行的 shell 脚本中return
和exit
之间的区别。即使我在其中使用return
,dash
也会退出脚本。if <command>
通过似乎违反直觉。在任何其他语言中,情况正好相反if ! some_command | some_other_command
将忽略 some_command 的状态。两种最常见的命令变通方法是set -o pipefail
(可能会更改程序其他部分的功能)或将if
语句移动到if [[ ${PIPESTATUS[0]} -ne 0 ]]
作为单独的后续命令(丑陋,但功能强大)。如果您使用的是set -e
,那么您还需要在使用第二种解决方案时将|| true
添加到管道的末尾,因为从if
提供的控制流中删除管道会导致它立即退出.