394

Is there any way to check if there is an error in executing a command?

Example :

test1=`sed -i "/:@/c connection.url=jdbc:oracle:thin:@$ip:1521:$dataBase" $search`
valid $test1

function valid () {
  if $test -eq 1; then
    echo "OK"
    else echo "ERROR" 
  fi
}

I already tried do that but it seems it isn't working. I don't how do that.

3

10 Answers 10

558

The return value is stored in $?. 0 indicates success, others indicates error.

some_command
if [ $? -eq 0 ]; then
    echo OK
else
    echo FAIL
fi

Like any other textual value, you can store it in a variable for future comparison:

some_command
retval=$?
do_something $retval
if [ $retval -ne 0 ]; then
    echo "Return code was not zero but $retval"
fi

For possible comparison operators, see man test.

9
  • That's nice ...can i hold the output error ??!! , because in this case i have 2 error : command error "text" ex, file not found and my error "text" Which is in this case failed for example
    – moata_u
    Mar 7, 2011 at 12:28
  • @moata_u: you can store the value in a variable as shown in my answer.
    – Lekensteyn
    Mar 7, 2011 at 13:14
  • @moata_u: You need to put a ; before the else and fi: `if ...; then ...; else ...; fi
    – Lekensteyn
    Mar 7, 2011 at 14:36
  • 4
    This is a useless use of test. Dec 1, 2014 at 22:04
  • 2
    @Blauhirn [ $? ] (or equivalently, test $?) does not work because $? evaluates to a number (0, 1, etc.) which is not null. See the docs for test: "If EXPRESSION is omitted, ‘test’ returns false. If EXPRESSION is a single argument, ‘test’ returns false if the argument is null and true otherwise."
    – Lekensteyn
    Mar 25, 2016 at 18:31
140

If you only need to know if the command succeeded or failed, don't bother testing $?, just test the command directly. E.g.:

if some_command; then
    printf 'some_command succeeded\n'
else
    printf 'some_command failed\n'
fi

And assigning the output to a variable doesn't change the return value (well, unless it behaves differently when stdout isn't a terminal of course).

if output=$(some_command); then
    printf 'some_command succeded, the output was «%s»\n' "$output"
fi

http://mywiki.wooledge.org/BashGuide/TestsAndConditionals explains if in more detail.

6
  • What if you want to do something other than branching like storing the boolean of whether it failed or not into a .ini? Then your output variable doesn't do that, but $? does, so you're incorrect in saying that testing the command directly is strictly better. Nov 30, 2017 at 15:53
  • 1
    Assigning the output to a variable may change the return value when one uses local command, i.e. local foo=$(false); echo $?; produces 0 on the output. But local is only relevant inside of bash functions.
    – Cromax
    Jan 22, 2019 at 13:45
  • I can't seem to use an else with the variable example. Any idea why? Sep 21, 2020 at 22:26
  • 1
    @Prometheus hard to say without seeing the code. Perhaps it incorrectly returns 0 in the case you considered a failure, or perhaps you added additional commands to the command substitution without using && between them.
    – geirha
    Sep 22, 2020 at 20:06
  • I'm not used to bash scripting. Does the if require some brackets or anything? Can I just have... if cd unreliable_dir; then
    – osullic
    Feb 12, 2021 at 15:38
55
command && echo OK || echo Failed
3
  • If command returns error on screen, how to hide it?
    – Sigur
    Apr 21, 2017 at 1:51
  • 1
    If command writes errors out to stderr, you can use the form command 2> /dev/null && echo OK || echo Failed. The 2> /dev/null redirects stderr output to /dev/null. However, some utilities will write errors to stdout (even though this is bad practice). In this case you can omit the 2 from the redirection, but you will lose any output from the command. This method of checking success is good for simple ternary logic but for more complex behavior it's best to check $? for command success, or use the if block method outlined in @geirha's answer.
    – codewario
    Jul 24, 2017 at 13:27
  • Note that this is not save in all cases. See: github.com/koalaman/shellcheck/wiki/SC2015 Apr 14, 2020 at 12:25
27

$? should contain the exit status of the previous command, which should be zero for no error.

So, something like;

cd /nonexistant
if [ $? -ne 0 ]
then
    echo failed
else
    echo success!
fi

for most cases, it's easier to use the && construct to chain commands that need to depend on each other. So cd /nonexistant && echo success! would not echo success because the command breaks before &&. The corollary of this is ||, where cd /nonexistant || echo fail would echo fail because cd failed (this becomes useful if you use something like ||exit, which will end the script if the previous command failed).

2
  • That's nice ...can i hold the output error ??!! , because in this case i have 2 error : command error "text" ex, file not found and my error "text" Which is in this case failed for example
    – moata_u
    Mar 7, 2011 at 12:24
  • @moata_u, see mywiki.wooledge.org/BashFAQ/002
    – geirha
    Mar 8, 2011 at 23:55
8
command && echo $? || echo $?
4
  • You mean command; echo $? ? Nov 16, 2018 at 10:32
  • 1
    No, my line is correct, it gives the actual result code as a number regardless if success or failure.
    – modrobert
    Nov 20, 2018 at 20:07
  • 1
    Ok, please explain the differences of these to me: true && echo $? || echo $? / true; echo $? and false && echo $? || echo $? / false; echo $? -- you'll find, they do the exact same thing :D Nov 21, 2018 at 11:07
  • Yes, the same result but without the condition. The original question asked was "How to check if a command succeeded?", this was based on previous answers. I guess a better example would be: command && echo "success: $?" || echo "fail: $?"
    – modrobert
    Nov 22, 2018 at 8:16
6

It should be noted that if...then...fi and &&/|| type of approach deals with exit status returned by command we want to test( 0 on success ); however, some commands don't return a non-zero exit status if command failed or couldn't deal with input. This means that the usual if and &&/|| approaches won't work for those particular commands.

For instance, on Linux GNU file still exits with 0 if it received a non-existing file as argument and find couldn't locate the file user specified.

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

In such cases, one potential way we could handle the situation is by reading stderr/stdin messages, e.g. those that returned by file command, or parse output of the command like in find. For that purposes, case statement could be used.

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

( This is a repost of my own answer on related question at unix.stackexchange.com )

5

As mentioned in many other answers, a simple test of $? will do, like this

if [ $? -eq 0 ]; then something; fi

If you want to test if the command failed, you can use a shorter version in bash (but perhaps overkill) as follows:

if (($?)); then something; fi

This works by using the (( )) arithmetic mode, so if the command returned success, i.e. $? = 0 then the test evaluates to ((0)) which tests as false, otherwise it will return true.

To test for success, you could use:

if ! (($?)); then something; fi

but it's already not much shorter than the first example.

0
2

For easier debugging, I make commands to only output errors with:

so [-tag] [commands]

After that $? is 0 if success, otherwise failure.

1

You can also configure bash to exit if a command fails, useful to avoid checks after every command. Place this at beginning of your script:

set -e
1

Prints the status of the last command

if [ $? == 0 ]; then echo passed;else echo failed; (exit 1); fi;

Section echo passed and echo failed can be modified to do whatever you want depending on the status of the last command.

Usage

echo test # supposed to pass
if [ $? == 0 ]; then echo passed;else echo failed; (exit 1); fi;

passed

blahblah # supposed to fail
if [ $? == 0 ]; then echo passed;else echo failed; (exit 1); fi;

failed

More fun using bash profile function:

function if_success() {
    if [ $? -eq 0 ]; then
        "$@"
    fi
}

echo base_echo
> base_echo
if_success echo awesome
> awesome

blah_blah
> command not found
if_success echo awesome
>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .