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.

Octavian Helm
  • 14,355
moata_u
  • 5,413

10 Answers10

559

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.

Lekensteyn
  • 174,277
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.

geirha
  • 46,101
  • 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. – Timothy Swan Nov 30 '17 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 '19 at 13:45
  • I can't seem to use an else with the variable example. Any idea why? – Hashim Aziz Sep 21 '20 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 '20 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 '21 at 15:38
  • @osullic [ is a command that returns 0 to indicate true, and 1 to indicate false. if runs one or more commands and checks the return value of the last one. If it returns 0, it does the then block, otherwise it jumps to else (if any). So yes, if cd dir; then is correct and sensible code. – geirha Feb 13 '21 at 16:59
55
command && echo OK || echo Failed
David Foerster
  • 36,264
  • 56
  • 94
  • 147
  • If command returns error on screen, how to hide it? – Sigur Apr 21 '17 at 01: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 '17 at 13:27
  • Note that this is not save in all cases. See: https://github.com/koalaman/shellcheck/wiki/SC2015 – Tobias Gaertner Apr 14 '20 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).

Shaun
  • 577
  • 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 07 '11 at 12:24
  • @moata_u, see http://mywiki.wooledge.org/BashFAQ/002 – geirha Mar 08 '11 at 23:55
8
command && echo $? || echo $?
modrobert
  • 117
  • You mean command; echo $? ? – Javier Buzzi Nov 16 '18 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 '18 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 – Javier Buzzi Nov 21 '18 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 '18 at 08: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 )

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
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.

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
jcarballo
  • 308
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 >

gndps
  • 119