117

I have a script which uses test command to check if $? (return code of last executed command) is not equal to zero. The code is as follows: -

$? is the exit status of the last command executed.

if (test $? -ne 0)
then
//statements//
fi

However this way of validation does not work for strings as get syntax error . Please suggest a suitable alternative to this.

3
  • 2
    in your example, $? is actually numeric but since you did use the square brackets which are the implied "test" command, you are getting syntax error, not because the exit code is a string. Commented Mar 18, 2013 at 7:12
  • Thanks ...so what do you suggets i should try ?? Commented Mar 18, 2013 at 7:21
  • 1
    please see my answer below and note the use of square brackets, not parentheses... Commented Mar 18, 2013 at 10:30

10 Answers 10

115

Put it in a variable first and then try to test it, as shown below

ret=$?
if [ $ret -ne 0 ]; then
        echo "In If"
else
        echo "In Else"
fi

This should help.


Edit: If the above is not working as expected then, there is a possibility that you are not using $? at right place. It must be the very next line after the command of which you need to catch the return status. Even if there is any other single command in between the target and you catching it's return status, you'll be retrieving the returns_status of this intermediate command and not the one you are expecting.

Sign up to request clarification or add additional context in comments.

6 Comments

I tried it ... fails to work in my case !! Any other suggestions please
@user1466466 - Can you expand on that? Are you sure $? is returning what you expect? Try echo $ret with this example to make sure.
This works for me. I am usually optimistic, so I do [ $ret -eq 0 ] instead, but it's a matter of taste.
@user1466466 I claim it should work. Can you provide evidence that it does not? In other words, never just say "it fails to work". Tell us what the command did, and what you want it to do.
@user1466466 Pls note that all the whitespaces matter. For example, there is a whitespace between [ and $ret and so on.
|
69

You don't need to test if $? is not 0. The shell provides && and || so you can easily branch based on implicit result of that test:

some_command && {
    # executes this block of code,
    # if some_command would result in:  $? -eq 0
} || {
    # executes this block of code,
    # if some_command would result in:  $? -ne 0
}

You can remove either branch, depending on what you want. So if you just want to test for failure (i.e. $? -ne 0):

some_command_returning_nonzero || {
    # executes this block of code when:     $? -ne 0
    # and nothing if the command succeeds:  $? -eq 0
}

However, the code you provided in the question works, as is. I'm confused that you got syntax errors & concluded that $? was a string. It's most likely that the errant code causing the syntax error was not provided with the question. This is especially evident because you claim that no one else's solutions work either. When this happens, you have to re-evaluate your assumptions.

NB: The code above may give confusing results if the code inside the braces returns an error. In that case simply use the if command instead, like this:

if some_command; then
    # executes this block of code,
    # if some_command would result in:  $? -eq 0
else
    # executes this block of code,
    # if some_command would result in:  $? -ne 0
fi

3 Comments

"$? -eq 0" means some_command executed with no errors ?? and "$? -ne 0" with errors??
@happy, yes, that's basically correct: $? -eq 0 means the last command exited with a status code of 0 (success). $? -ne 0 means the last command exited with a non-zero status code (usually due to an error).
I've switched from pipes to if block in similar UC, since it is wanted to exit script in error case. ( stackoverflow.com/a/20799125/1456164 )
23

Try this after execution of your script :

if [ $? -ne 0 ];
then
//statements//
fi

Comments

3

I don't know how you got a string in $? but you can do:

if [[ "x$?" == "x0" ]]; then
   echo good
fi

2 Comments

I tried it ... it fails to check the condition !! Any other suggestions please
[[ ... ]] may not be available in the user's shell.
3

This is a solution that came up with for a similar issue

exit_status () {
if [ $? = 0 ]
then
    true
else
    false
fi
}

usage:

do-command exit_status && echo "worked" || echo "didnt work"

2 Comments

A simpler alternative would define it like this: exit_status() { test $? -eq 0; }. And in your example you could eliminate the extraneous exit_status function altogether and do: do-command && echo "worked" || echo "didn't work".
Or you could just do this: stackoverflow.com/a/41308634/303114
1
<run your last command on this line>
a=${?}
if [ ${a} -ne 0 ]; then echo "do something"; fi

use whatever command you want to use instead of the echo "do something" command

Comments

1
if [ $var1 != $var2 ] 
then 
echo "$var1"
else 
echo "$var2"
fi

Comments

0
function assert_exit_code {
    rc=$?; if [[ $rc != 0 ]]; then echo "$1" 1>&2; fi
}

...

execute.sh

assert_exit_code "execute.sh has failed"

Comments

0

put set -o pipefail at start of any script, to return any failure

incase you do, and the test fails but the tee doesnt. By default $? just takes the last commands success, in this case the "tee" command

test | tee /tmp/dump
[ $? -ne 0 ] && echo "failed"

Comments

0

I put together some code that may help to see how return value vs returned strings works. There may be a better way, but this is what I found through testing.

#!/bin/sh
#
# ro
#

pass(){
  echo passed
  return 0;   # no errors
}
fail(){
  echo failed
  return 1;   # has an error
}
t(){
  echo true, has error
}
f(){
  echo false, no error
}

dv=$(printf "%60s"); dv=${dv// /-}

echo return code good for one use, not available for echo
echo $dv
pass
[ $? -gt 0 ] && t || f
echo "function pass: \$? $?" ' return value is gone'
echo
fail
[ $? -gt 0 ] && t || f
echo "function fail: \$? $?" ' return value is gone'
echo

echo save return code to var k for continued usage
echo $dv
pass
k=$?
[ $k -gt 0 ] && t || f
echo "function pass: \$k $k"
echo
fail
k=$?
[ $k -gt 0 ] && t || f
echo "function fail: \$k $k"
echo

# direct evaluation of the return value
# note that (...) and $(...) executes in a subshell
# with return value to calling shell
# ((...)) is for math/string evaluation

echo direct evaluations of the return value:
echo '  by if (pass) and if (fail)'
echo $dv
if (pass); then
  echo pass has no errors
else
  echo pass has errors
fi
if (fail); then
  echo fail has no errors
else
  echo fail has errors
fi

# this code results in error because of returned string (stdout)
# but comment out the echo statements in pass/fail functions and this code succeeds
echo
echo '  by if $(pass) and if $(fail) ..this succeeds if no echo to stdout from function'
echo $dv
if $(pass); then
  echo pass has no errors
else
  echo pass has errors
fi
if $(fail); then
  echo fail has no errors
else
  echo fail has errors
fi

echo
echo '  by if ((pass)) and if ((fail)) ..this always fails'
echo $dv
if ((pass)); then
  echo pass has no errors
else
  echo pass has errors
fi
if ((fail)); then
  echo fail has no errors
else
  echo fail has errors
fi

echo 
s=$(pass)
r=$?
echo pass, "s: $s  ,  r: $r"
s=$(fail)
r=$?
echo fail, "s: $s  ,  r: $r"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.