如何使用“if”语句检查退出状态

How to check the exit status using an 'if' statement

提问人:deadcell4 提问时间:10/31/2014 最后编辑:Paulo Mattosdeadcell4 更新时间:7/18/2023 访问量:834850

问:

检查语句中的退出状态以回显特定输出的最佳方法是什么?if

我正在考虑它是:

if [ $? -eq 1 ] 
then
    echo "blah blah blah"
fi

我还遇到的问题是,该语句位于语句之前,仅仅是因为它必须具有该退出代码。另外,我知道我做错了什么,因为退出显然会退出程序。exitif

bash shell if-statement 错误处理 exit-code

评论

4赞 RedX 10/31/2014
Plaese 发布您的完整脚本(或至少更广泛的范围)。否则这似乎很好。
9赞 twalberg 10/31/2014
如果您需要在两个不同的地方使用某些特定程序调用的退出代码,那么您需要保留它 - 类似于some_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}

答:

548赞 Etan Reisner 10/31/2014 #1

每个运行的命令都有一个退出状态。

该检查正在查看在该行运行之前最近完成的命令的退出状态。

如果您希望脚本在该测试返回 true(上一个命令失败)时退出,那么您将(或其他任何内容)放在该块中。exit 1ifecho

话虽如此,如果您正在运行命令并想要测试其输出,则使用以下命令通常更直接。

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

请注意,这些都不关心错误代码是什么。如果您知道您只关心特定的错误代码,则需要手动检查。$?

评论

34赞 gboffi 10/31/2014
@deadcell4 当需要在程序失败时终止 shell 脚本时,以下习语很有用a_command || return 1
22赞 Etan Reisner 10/31/2014
@gboffi仅适用于函数和源脚本。您需要另一种情况(在函数和源脚本中执行太多操作)。但是,是的,如果您不需要任何特定的清理或额外的输出,这当然是一个合理的模式。returnexit
2赞 gboffi 10/31/2014
我不得不说,许多现代 linux 发行版中默认的非交互式 shell 并不关心执行的 shell 脚本之间和内部的区别。 退出脚本,即使我在其中使用。dashreturnexitdashreturn
3赞 sjw 6/4/2019
最后两次检查背后的逻辑是什么?如果退出代码为 0,则条件通过似乎有悖常理。在任何其他语言中,情况正好相反if <command>
8赞 Alex Jansen 7/4/2019
重要提示:这不适用于管道。 将忽略some_command状态。两个最命令的解决方法是(可能会更改程序其他部分的功能)或将语句作为单独的后续命令移动到(丑陋,但功能正常)。如果您正在使用,那么在使用第二种解决方案时,您还需要添加到管道的末端,因为从提供的控制流中移除管道会导致它立即退出。if ! some_command | some_other_commandset -o pipefailifif [[ ${PIPESTATUS[0]} -ne 0 ]]set -e|| trueif
67赞 chepner 10/31/2014 #2

$?是与任何其他参数一样的参数。您可以保存其值以在最终调用 之前使用 。exit

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status
413赞 Oo.oO 8/22/2017 #3

请注意,退出代码 != 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

评论

3赞 anr78 4/19/2018
您必须在 retVal 上进行测试,因为 $?在分配 retVal 之后,它不是命令的返回值。
1赞 Oo.oO 4/19/2018
不是真的:mywiki.wooledge.org/BashFAQ/002 - 但是,我同意编辑可以提高可读性。
2赞 anr78 4/19/2018
刚刚找到了这篇文章,解释了它 stackoverflow.com/questions/20157938/......
1赞 Oo.oO 6/18/2019
@jww - 好吧,这不太适合违反惯例(gnu.org/software/bash/manual/html_node/Exit-Status.html)。但是,好吧,没有什么可以阻止的。如果开发人员选择了这种方式,那是他们的选择。但是,他们的选择并没有使规范被打破:)dnf
1赞 Timo 9/25/2021
# will fail for error codes > 1但检查错误代码是否等于 1?$retVal -eq 1
93赞 Catskul 5/2/2019 #4

显式语句的替代方法if

微:

test $? -eq 0 || echo "something bad happened"

完成:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened";
exit $EXITCODE
36赞 codeforester 7/9/2019 #5

只是为了补充有用和详细的答案

如果必须显式检查退出代码,最好使用算术运算符 ,这样:(( ... ))

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 中的错误处理的相关答案:

评论

10赞 quapka 8/13/2020
您能详细说明一下为什么使用算术运算符更好吗?
1赞 yuyu5 12/4/2021
这个答案其实是不正确的。你不能在这样的布尔检查中使用,无论你是否使用,或者因为它没有像普通变量那样被解析(相关描述)。$?(( $? != 0 ))[[ $? -ne 0 ]]
2赞 yuyu5 12/4/2021
为什么算术更好:不是,只是个人喜好。我更喜欢它 b/c 它更短,即 而不是 OR,但这并不一定意味着它更好。事实上,我喜欢使用的快捷方式会让任何不太了解 Bash 的人感到困惑。(( $retVal )) && echo 'ERROR'(( $retVal != 0 ))[[ $retVal -ne 0 ]]
53赞 dtk 7/13/2020 #6

作为记录,如果脚本使用 (或 ) 运行,因此您无法直接检查(因为脚本将在除零以外的任何返回代码上终止),但想要处理特定代码,@gboffis注释很棒:set -e#!/bin/bash -e$?

/some/command || error_code=$?
if [ "${error_code}" -eq 2 ]; then
   ...

评论

2赞 Justin 4/9/2021
如果在 PATH 中,这不会中断吗? 未设置。/some/commanderror_code
0赞 dtk 4/9/2021
我看不出这会有什么干扰。您可以在现有目录上尝试,该目录应返回 1。您确定您尝试的命令确实返回了 0 以外的退出代码吗? 例如,在不存在的文件中打印错误,但仍返回 0 🤷/bin/mkdir/usr/bin/file
0赞 Leponzo 1/9/2022
@Justin,我同意。我觉得最好用|| is_fail=true; if [ "$is_fail" = true ]; then . . .
2赞 Roland Weber 8/3/2023
error_code仅当返回状态为非零时才会设置。/some/command
18赞 Nishant 9/14/2020 #7

如果你正在编写一个函数(这始终是首选的),你可以像这样传播错误:

function()
{
    if <command>; then
        echo worked
    else
        return
    fi
}

现在,调用者可以按预期执行操作!如果你在块中有很多事情要做,这很有用,等等(否则有单行)。可以使用命令轻松测试它。function && nextiffalse

12赞 Aviel Yosef 1/18/2021 #8

使用 Z shell (),您可以简单地使用:zsh

if [[ $(false)? -eq 1 ]]; then echo "yes" ;fi

使用 Bash 和 is on 时,可以使用:set -e

false || exit_code=$?
if [[ ${exit_code} -ne 0 ]]; then echo ${exit_code}; fi
2赞 JonC 6/8/2022 #9

这可能只在有限的用例中有用,当我需要捕获命令的输出并在退出代码报告出现问题时将其写入日志文件时,我特别使用它。

RESULT=$(my_command_that_might_fail)
if (exit $?) 
then
    echo "everything went fine."    
else
    echo "ERROR: $RESULT" >> my_logfile.txt
fi
1赞 Chen Tian 11/4/2022 #10

下面的测试脚本适用于

  • 简单的 bash 测试命令
  • 多个测试命令
  • 包含管道的 bash 测试命令:
if [[ $(echo -en "abc\n def" |grep -e "^abc") && ! $(echo -en "abc\n def" |grep -e "^def") ]] ; then
  echo "pipe true"
else
  echo "pipe false"
fi
if [[ $(echo -en "abc\n def" |grep -e "^abc") && $(echo -en "abc\n def" |grep -e "^def") ]] ; then
  echo "pipe true"
else
  echo "pipe false"
fi

输出为:

pipe true
pipe false
12赞 ivanko337 1/6/2023 #11

你可以添加这个if语句:

if [ $? -ne 0 ];
then
    echo 'The previous command was not executed successfully';
fi
3赞 Colin 't Hart 3/25/2023 #12

我缺少最简单的解决方案,就是使用运算符:&&

command --with parameters && echo "Command completed succesfully"

-- 假设成功时返回 0,失败时返回非零,正如 Bash 所期望的那样(这与许多编程语言相反!command

该运算符可用于故障:||

commamnd --with parameters || echo "Command failed"
0赞 Abdull 7/18/2023 #13

这是一个可以正常处理的解决方案:set -euo pipefail

# ...

some-command && true
SOME_COMMAND_EXIT_STATUS="$?"

# ... 

#!/bin/bash
set -euo pipefail

# due to "set -e", using " ... && true" construct to avoid script from
# exiting immediately on expectable nonzero exit code.
# As per the Bash Reference Manual:
#
#   "[...] The shell does not exit if the command that fails is
#    [...] part of any command executed in a && or || list
#    [as long as it isn't the final command in this list]"
#
# see https://www.gnu.org/software/bash/manual/html_node/Lists.html
# see "-e" at https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

some-command && true
SOME_COMMAND_EXIT_STATUS="$?"

if [[ "$SOME_COMMAND_EXIT_STATUS" == 4 ]]; then
  echo "some-command exit status was 4"
else
  echo "some-command exit status was unequal 4"
fi