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

dea*_*ll4 203 error-handling bash shell if-statement

我想知道在if语句中检查退出状态以回显特定输出的最佳方法是什么.

我在想它

if [ $? -eq 1 ]
then
   echo "blah blah blah"
fi
Run Code Online (Sandbox Code Playgroud)

我也遇到的问题是,exit语句在if语句之前只是因为它必须有退出代码,我知道我也做错了,因为退出wold显然会退出程序.

Eta*_*ner 218

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

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

如果您希望您的脚本在该测试返回true时退出(前一个命令失败),那么您exit 1在该if块之后放置(或者其他)echo.

如果您正在运行该命令并希望使用以下内容测试其输出,那么通常会更直截了当.

if some_command; then
    echo command returned true
else
    echo command returned some error
fi
Run Code Online (Sandbox Code Playgroud)

或者将其!用于否定

if ! some_command; then
    echo command returned some error
else
    echo command returned true
fi
Run Code Online (Sandbox Code Playgroud)

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

  • @ deadcell4当需要在程序失败时终止shell脚本时,以下习语很有用`a_command || 返回1` (9认同)
  • @gboffi`return`仅适用于函数和源脚本.对于另一种情况,你需要`exit`(在函数和源代码中做太多).但是,如果您不需要任何特定的清理或额外输出,这肯定是一个合理的模式. (9认同)
  • 最后两次检查背后的逻辑是什么?如果退出代码为 0,条件“if <command>”就会通过,这似乎违反直觉。在任何其他语言中,情况恰恰相反 (3认同)
  • 我不得不说,许多现代 Linux 发行版中默认的非交互式 shell“dash”并不关心执行的 shell 脚本中“return”和“exit”之间的区别。即使我在其中使用了“return”,“dash”也会退出脚本。 (2认同)
  • 重要说明:这不适用于管道。`如果!some_command | some_other_command`将忽略some_command的状态。最常用的两个命令解决方法是:设置-o pipefail(可能会更改程序其他部分的功能)或将if语句移至if [[$ $ PIPESTATUS [0]} -ne 0]]。作为单独的后续命令(难看,但可以正常使用)。如果您使用`set -e`,那么您还需要添加`||。如果使用第二种解决方案,则返回true到管道末端,因为从if所提供的控制流中移除管道会导致其立即退出。 (2认同)

Oo.*_*.oO 143

请注意,退出代码!= 0用于报告错误.所以,最好这样做:

retVal=$?
if [ $retVal -ne 0 ]; then
    echo "Error"
fi
exit $retVal
Run Code Online (Sandbox Code Playgroud)

代替

# will fail for error codes > 1
retVal=$?
if [ $retVal -eq 1 ]; then
    echo "Error"
fi
exit $retVal
Run Code Online (Sandbox Code Playgroud)

  • 您必须测试 retVal,因为 $? retVal 赋值后不是命令的返回值。 (3认同)
  • 刚刚发现这篇文章解释了它 /sf/ask/1411055691/ (2认同)

che*_*ner 37

$?是一个像任何其他参数.您可以在最终调用之前保存其值exit.

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status
Run Code Online (Sandbox Code Playgroud)


dtk*_*dtk 21

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

/some/command || error_code=$?
if [ "${error_code}" -eq 2 ]; then
   ...
Run Code Online (Sandbox Code Playgroud)

  • 如果 `/some/command` 在 PATH 中,这不会中断吗?未设置“error_code”。 (2认同)
  • 仅当“/some/command”返回非零状态时才会设置“error_code”。 (2认同)

iva*_*337 15

你可以添加这个 if 语句:

if [ $? -ne 0 ];
then
    echo 'The previous command was not executed successfully';
fi
Run Code Online (Sandbox Code Playgroud)


Cat*_*kul 9

替代明确if陈述

最少:

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

完成:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened"; 
exit $EXITCODE
Run Code Online (Sandbox Code Playgroud)


Nis*_*ant 6

如果你正在编写一个函数——这总是首选——你可以像这样传播错误:

function()
{
    if <command>; then
        echo worked
    else
        return
    fi
}
Run Code Online (Sandbox Code Playgroud)

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


小智 6

使用zsh您可以简单地使用:

if [[ $(false)? -eq 1 ]]; then echo "yes" ;fi
Run Code Online (Sandbox Code Playgroud)

当使用bash& 时set -e,您可以使用:

false || exit_code=$?
if [[ ${exit_code} -ne 0 ]]; then echo ${exit_code}; fi
Run Code Online (Sandbox Code Playgroud)


cod*_*ter 5

只是添加到有用和详细的答案

如果必须显式检查退出代码,则最好通过以下方式使用算术运算符(( ... ))

run_some_command
(($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }
Run Code Online (Sandbox Code Playgroud)

或者,使用以下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
Run Code Online (Sandbox Code Playgroud)

有关Bash中错误处理的相关答案:

  • 您能否详细说明一下为什么_最好使用算术运算符_? (7认同)
  • 为什么算术更好:这不是,只是个人喜好。我更喜欢它,因为它更短,即 `(( $retVal )) &amp;&amp; echo 'ERROR'` 而不是 `(( $retVal != 0 ))` 或 `[[ $retVal -ne 0 ]]` 但是这并不一定意味着它更好。事实上,我喜欢使用的快捷方式会让那些不太了解 Bash 的人感到困惑。 (2认同)