如何使用“if”语句检查退出状态
Posted
技术标签:
【中文标题】如何使用“if”语句检查退出状态【英文标题】:How to check the exit status using an 'if' statement 【发布时间】:2014-12-27 19:59:41 【问题描述】:在 if 语句中检查退出状态以回显特定输出的最佳方法是什么?
我觉得是
if [ $? -eq 1 ]
then
echo "blah blah blah"
fi
我还遇到的问题是 exit 语句位于 if 语句之前,因为它必须具有退出代码。另外,我知道我做错了什么,因为 exit 显然会退出程序。
【问题讨论】:
请发布您的完整脚本(或至少更广泛的范围)。否则这似乎很好。 如果您需要在两个不同的地方使用某个特定程序调用的退出代码,那么您需要保留它——类似于some_program; rc=$?; if [ $rc -eq 1 ] .... fi ; exit $rc
【参考方案1】:
每个运行的命令都有一个退出状态。
该检查正在查看在该行运行之前最近完成的命令的退出状态。
如果您希望 您的 脚本在该测试返回 true(上一个命令失败)时退出,那么您将 exit 1
(或其他)放在 if
块内 echo
之后。
话虽如此,如果您正在运行命令并想要测试其输出,则使用以下命令通常更直接。
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
请注意,尽管这些都不关心错误代码是什么。如果您知道您只关心特定的错误代码,那么您需要手动检查$?
。
【讨论】:
@deadcell4 当需要在程序失败时终止 shell 脚本时,以下成语很有用a_command || return 1
@gboffi return
仅适用于函数和源脚本。对于另一种情况,您需要exit
(它在函数和源脚本中做了太多)。但是,是的,如果您不需要任何特定的清理或额外的输出,这当然是一个合理的模式。
我不得不说dash
,许多现代Linux发行版中默认的非交互式shell,并不关心执行的shell脚本中return
和exit
之间的区别。 dash
退出脚本,即使我在其中使用 return
。
最后两次检查背后的逻辑是什么?如果退出代码为 0,则条件 if <command>
通过似乎违反直觉。在任何其他语言中,情况正好相反
重要提示:这不适用于管道。 if ! some_command | some_other_command
将忽略 some_command 的状态。两种最常见的命令变通方法是 set -o pipefail
(可能会更改程序其他部分的功能)或将 if
语句移动到 if [[ $PIPESTATUS[0] -ne 0 ]]
作为单独的后续命令(丑陋,但功能齐全)。如果您使用的是set -e
,那么在使用第二种解决方案时,您还需要将|| true
添加到管道的末尾,因为从if
提供的控制流中删除管道会导致它立即退出.【参考方案2】:
请注意,退出代码 != 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
【讨论】:
您必须在 retVal 上进行测试,因为 $?分配 retVal 后不是您命令的返回值。 并非如此:mywiki.wooledge.org/BashFAQ/002 - 但是,我同意编辑可以提高可读性。 刚刚发现这篇解释它的帖子***.com/questions/20157938/… @jww - 好吧,违背惯例(gnu.org/software/bash/manual/html_node/Exit-Status.html)并不是一个好主意。但是,好吧,没有什么可以阻止这一点。如果dnf
开发人员选择了这种方式,那是他们的选择。但是,他们的选择并没有破坏规范:)
# will fail for error codes > 1
但$retVal -eq 1
检查错误代码是否等于 1?【参考方案3】:
显式if
语句的替代方法
最低限度:
test $? -eq 0 || echo "something bad happened"
完成:
EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened";
exit $EXITCODE
【讨论】:
【参考方案4】:$?
是一个和其他参数一样的参数。您可以在最终调用 exit
之前保存其值以供使用。
exit_status=$?
if [ $exit_status -eq 1 ]; then
echo "blah blah blah"
fi
exit $exit_status
【讨论】:
【参考方案5】:只是为了补充有用和详细的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 错误处理的相关回答:
Raise error in a Bash script【讨论】:
您能否详细说明为什么最好使用算术运算符? 这个答案实际上是不正确的。无论您是使用(( $? != 0 ))
还是[[ $? -ne 0 ]]
,您都不能在这样的布尔检查中使用$?
,因为它不像普通变量那样被解析(related description)。
为什么算术更好:不是,只是个人喜好。我更喜欢它,因为它更短,即(( $retVal )) && echo 'ERROR'
而不是(( $retVal != 0 ))
或[[ $retVal -ne 0 ]]
,但这并不一定意味着它更好。事实上,我喜欢使用的快捷方式会让那些不太了解 Bash 的人感到困惑。【参考方案6】:
作为记录,如果脚本使用set -e
(或#!/bin/bash -e
)运行,因此您不能直接检查$?
(因为脚本将在除零以外的任何返回码处终止),但想要处理一个特定的代码,@gboffis comment 很棒:
/some/command || error_code=$?
if [ "$error_code" -eq 2 ]; then
...
【讨论】:
如果/some/command
在路径中,这不会中断吗? error_code
未设置。
我不明白这会如何干扰。您可以在现有目录上尝试/bin/mkdir
,它应该返回 1。您确定您尝试的命令确实返回了 0 以外的退出代码? /usr/bin/file
在不存在的文件上例如打印错误但仍返回 0 ?
@贾斯汀,我同意。我认为最好使用|| is_fail=true; if [ "$is_fail" = true ]; then . . .
【参考方案7】:
如果你正在编写一个函数——这总是首选——你可以像这样传播错误:
function()
if <command>; then
echo worked
else
return
fi
现在,调用者可以按预期执行function && next
之类的操作!如果您在if
块等中有很多事情要做,这很有用(否则只有一个行)。可以使用false
命令轻松测试。
【讨论】:
【参考方案8】:使用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
【讨论】:
以上是关于如何使用“if”语句检查退出状态的主要内容,如果未能解决你的问题,请参考以下文章
Facebook SDK iOS 应用在应用退出时保持登录状态
python - 如何在python中使用IF语句检查两个列表的元素是不是相等?
R语言使用Repeat函数多次执行代码块内的语句,实现循环执行任务的功能:repeat没有提供任何检查条件,所以编码者必须给出退出重复循环的条件(一般使用if和break)