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

579,441

Solution 1

Every command that runs has an exit status.

That check is looking at the exit status of the command that finished most recently before that line runs.

If you want your script to exit when that test returns true (the previous command failed) then you put exit 1 (or whatever) inside that if block after the echo.

That being said, if you are running the command and are wanting to test its output, using the following is often more straightforward.

if some_command; then
    echo command returned true
else
    echo command returned some error
fi

Or to turn that around use ! for negation

if ! some_command; then
    echo command returned some error
else
    echo command returned true
fi

Note though that neither of those cares what the error code is. If you know you only care about a specific error code then you need to check $? manually.

Solution 2

Note that exit codes != 0 are used to report errors. So, it's better to do:

retVal=$?
if [ $retVal -ne 0 ]; then
    echo "Error"
fi
exit $retVal

instead of

# will fail for error codes == 1
retVal=$?
if [ $retVal -eq 1 ]; then
    echo "Error"
fi
exit $retVal

Solution 3

An alternative to an explicit if statement

Minimally:

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

Complete:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened";
exit $EXITCODE

Solution 4

$? is a parameter like any other. You can save its value to use before ultimately calling exit.

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status

Solution 5

For the record, if the script is run with set -e (or #!/bin/bash -e) and you therefore cannot check $? directly (since the script would terminate on any return code other than zero), but want to handle a specific code, @gboffis comment is great:

/some/command || error_code=$?
if [ "${error_code}" -eq 2 ]; then
   ...
Share:
579,441
deadcell4
Author by

deadcell4

Updated on January 20, 2022

Comments

  • deadcell4
    deadcell4 over 2 years

    What would be the best way to check the exit status in an if statement in order to echo a specific output?

    I'm thinking of it being

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

    The issue I am also having is that the exit statement is before the if statement simply because it has to have that exit code. Also, I know I'm doing something wrong since the exit would obviously exit the program.

  • gboffi
    gboffi over 9 years
    @deadcell4 When one needs to terminate a shell script on a program failure, the following idiom is useful a_command || return 1
  • Etan Reisner
    Etan Reisner over 9 years
    @gboffi return only works in a function and a sourced script. You need exit for the other case (which does too much in a function and a sourced script). But yes, that's certainly a reasonable pattern if you don't need any specific cleanup or extra output.
  • gboffi
    gboffi over 9 years
    I have to say that dash, the default non-interactive shell in many modern linux distributions, don't care of the distinction between return and exit inside of executed shell scripts. dash exits the script even if I use return in it.
  • anr78
    anr78 about 6 years
    You must test on retVal, because $? after the assignment of retVal is not the return value from your command.
  • Oo.oO
    Oo.oO about 6 years
    Not really: mywiki.wooledge.org/BashFAQ/002 - however, I agree that edit improves the readability.
  • anr78
    anr78 about 6 years
    Just found this post that explains it stackoverflow.com/questions/20157938/…
  • sjw
    sjw almost 5 years
    What is the logic behind the last two checks? It seems counter-intuitive that the condition if <command> passes if the exit code is 0. In any other language it would be the other way around
  • jww
    jww almost 5 years
    dnf check-update returns 0 (no updates), 100 (updates available) or 1 (error).
  • Oo.oO
    Oo.oO almost 5 years
    @jww - well, that's not quite a good idea to go against convention (gnu.org/software/bash/manual/html_node/Exit-Status.html). But, well, there is nothing to prevent that. If dnf developers have chosen this way, it's their choice. But still, their choice doesn't make the specification to be broken :)
  • Alex Jansen
    Alex Jansen almost 5 years
    IMPORTANT NOTE: This won't work for pipes. if ! some_command | some_other_command will ignore the status of some_command. The two most command workarounds are to set -o pipefail (may change functionality in other parts of your program) or to move the if statement to if [[ ${PIPESTATUS[0]} -ne 0 ]] as a separate follow-up command (ugly, but functional). If you're using set -e then you'll also want to add || true to the end of the pipe when using the second solution since removing the pipe from the control flow offered by if would otherwise cause it to immediately exit.
  • quapka
    quapka over 3 years
    Could you elaborate on why it is better to use the arithmetic operator?
  • manu
    manu over 3 years
    What about grep; which has 3 possible exit codes: 0 - something was selected, 1 - nothing; 2 - an error.
  • chrisinmtown
    chrisinmtown about 3 years
    Is there a way to fetch the error code in the "then" branch above, I know it returned non-zero but can I get exactly what flavor of non-zero?
  • Justin
    Justin about 3 years
    Doesn't this break if /some/command is in the PATH? error_code is not set.
  • dtk
    dtk about 3 years
    I don't see how that would interfere. You can try /bin/mkdir on an existing directory, that should return 1. Are you certain the command you tried did return an exit code other than 0? /usr/bin/file on an non-existant file for example prints an error but still returns 0 🤷
  • Timo
    Timo over 2 years
    # will fail for error codes > 1 but $retVal -eq 1 checks for error code equal 1?
  • Oo.oO
    Oo.oO over 2 years
    @Timo - true, true; This is a perfect sample of why shouldn't you trust comments - they become outdated at some point. Thanks for the remark.
  • yuyu5
    yuyu5 over 2 years
    This answer is actually incorrect. You can't use $? in a boolean check like that, regardless of whether you use (( $? != 0 )) or [[ $? -ne 0 ]] because it doesn't get parsed like normal vars do (related description).
  • yuyu5
    yuyu5 over 2 years
    Re why arithmetic is better: It's not, just personal preference. I like it more b/c it's shorter, i.e. (( $retVal )) && echo 'ERROR' instead of (( $retVal != 0 )) or [[ $retVal -ne 0 ]] but that doesn't necessarily mean it's better. In fact, the shortcut I like to use would be confusing to anyone who doesn't know Bash all that well.
  • Leponzo
    Leponzo over 2 years
    @Justin, I agree. I think it's better to use || is_fail=true; if [ "$is_fail" = true ]; then . . .