deadcell4
deadcell4

Reputation: 6725

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

What would be the best way to check the exit status in an if statement 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.

Upvotes: 645

Views: 984471

Answers (15)

hitsmaxft
hitsmaxft

Reputation: 31

you may use if with your target command directly to check exit code is 0 or non-zero

if ps 123 >/dev/null ; then
   echo 'process id 123 exists'
else
   echo 'process id 123 not found'
fi

or use [[ for more complex expressions


# use || to ignore return value of  first part in expression 

if [[ $(ps 123>/dev/null ) || $? -eq 0  ]] ; then
 echo "yes" 
else
  echo "no"
fi

Upvotes: 2

HumbleEngineer
HumbleEngineer

Reputation: 341

@Roland's comment on @dtk's answer is correct. If you have to deal with potentially-failing commands inside bash -e or with set -e then the following will allow capturing the return code and stdout no matter what, then testing return code and/or output and reacting accordingly:

some_command > output.out && ret=$? || ret=$? ; true
if [ $ret -eq 0 ] ; then
    commands_if_command_succeeded
    # e.g. 
    grep -q something output.out || echo "something missing" && exit 1
    echo something is there, all good
else
    commands_if_command_failed
fi

If you only want commands_if_command_failed then change -eq to -ne and delete commands_if_command_succeeded block and else line. Or you could use $ret in a case statement as others have suggested.

Upvotes: 2

Colin 't Hart
Colin 't Hart

Reputation: 7739

I'm missing the most simple solution, which is just to use the && operator:

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

-- assuming command returns 0 on success, and non-zero on failure as Bash expects (which is kind of the opposite of many programming languages!)

The || operator can be used for failure:

command --with parameters || echo "Command failed"

Upvotes: 6

Abdull
Abdull

Reputation: 27872

This is a solution handling set -euo pipefail gracefully:

# ...

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

# ... 

Example

#!/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

Upvotes: 2

ivanko337
ivanko337

Reputation: 399

you can just add this if statement:

if [ $? -ne 0 ];
then
    echo 'The previous command was not executed successfully';
fi

Upvotes: 18

Chen Tian
Chen Tian

Reputation: 109

Below test scripts below work for

  • simple bash test commands
  • multiple test commands
  • bash test commands with pipe included:
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

The output is:

pipe true
pipe false

Upvotes: 1

JonC
JonC

Reputation: 978

This might only be useful in a limited set of use-cases, I use this specifically when I need to capture the output from a command and write it to a log file if the exit code reports that something went wrong.

RESULT=$(my_command_that_might_fail)
if (exit $?) 
then
    echo "everything went fine."    
else
    echo "ERROR: $RESULT" >> my_logfile.txt
fi

Upvotes: 2

Aviel Yosef
Aviel Yosef

Reputation: 581

Using Z shell (zsh) you can simply use:

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

When using Bash and set -e is on, you can use:

false || exit_code=$?
if [[ ${exit_code} -ne 0 ]]; then echo ${exit_code}; fi

Upvotes: 14

Nishant
Nishant

Reputation: 21934

If you are writing a function – which is always preferred – you can propagate the error like this:

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

Now, the caller can do things like function && next as expected! This is useful if you have a lot of things to do in the if block, etc. (otherwise there are one-liners for this). It can easily be tested using the false command.

Upvotes: 21

Catskul
Catskul

Reputation: 19460

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

Upvotes: 105

Oo.oO
Oo.oO

Reputation: 13435

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

Upvotes: 462

Etan Reisner
Etan Reisner

Reputation: 81052

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.

Upvotes: 587

dtk
dtk

Reputation: 2546

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
   ...

Upvotes: 61

codeforester
codeforester

Reputation: 43109

Just to add to the helpful and detailed answer:

If you have to check the exit code explicitly, it is better to use the arithmetic operator, (( ... )), this way:

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

Or, use a case statement:

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

Related answer about error handling in Bash:

Upvotes: 37

chepner
chepner

Reputation: 532418

$? 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

Upvotes: 72

Related Questions