How to use case statement to deal with multiple return values

12,705

Solution 1

You can't use

case $(somecommand) in ...

to test the exit status of somecommand because the command substitution expands to the output of the command, not its exit status.

Using $(true) doesn't work since true doesn't produce any output on standard output.

You could do

{ somecommand; err="$?"; } || true

case $err in
    0) echo success ;;
    *) echo fail
esac

This will stop the script running under errexit (-e) from exiting.

From the bash manual (from the description of set -e):

The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !.

In this case, with only the possibilities to either succeed or to fail, it would be easier to just do

if somecommand; then
    echo success
else
    echo fail
fi

Solution 2

The syntax

`command`

means to substitute the standard output of the command into the original command line. The output is not the same thing as the exit status. The true command doesn't produce any output, so your command is equivalent to:

case "" in
0) echo success ;;
*) echo fail ;;
esac

You can solve your problem this way:

case `my_command; echo $?` in 
...
esac

BTW, in the if command you don't need the backticks, it should just be:

if true
then echo successs
else echo fail
fi

Solution 3

Even with set -e you can still do:

if my_command
then
    echo success
else
    res=$?
    case $res in
      …
    esac
fi

Edit: you could also do

res=0
my_command || res=$?
case $res in
    …
esac
Share:
12,705

Related videos on Youtube

Paulo Matos
Author by

Paulo Matos

Updated on September 18, 2022

Comments

  • Paulo Matos
    Paulo Matos almost 2 years

    Take a look at these attempts:

    $ case `true` in 0) echo success ;; *) echo fail ;; esac
    fail
    $ if `true` ; then
    > echo "success"
    > else 
    > echo "fail"
    > fi
    success
    

    Now, why is the case statement failing? You might wonder why I don't just use the if statement and I shall explain. My command if complex and might return different return codes on which I want act on. I don't want to run the command multiple times and I can't do:

    my_command
    res = $?
    case $? in
    ...
    esac
    

    This is because I use set -e in my script and therefore if my_command returns failure the script aborts.

    But I have a workaround...

    set +e
    my_command
    res=$?
    set -e
    case $? in 
    ...
    esac
    

    But this is ugly, so returning to my initial question... why can I just use the case my_command in ... esac version?