Pattern: Use of indirect exit code check
Issue: -
Running a command and then checking its exit status $?
against 0 is redundant.
Instead of just checking the exit code of a command, it checks the exit code of a command (e.g. [
) that checks the exit code of a command.
Apart from the redundancy, there are other reasons to avoid this pattern:
- Since the command and its status test are decoupled, inserting an innocent command like
echo "make finished"
aftermake
will cause theif
statement to silently start comparingecho
's status instead. - Scripts that run or are called with
set -e
akaerrexit
will exit immediately if the command fails, even though they're followed by a clause that handles failure. - The value of
$?
is overwritten by[
/[[
, so you can't get the original value in the relevant then/else block (e.g.if somecmd; then echo "Success"; else echo "Failed with $?"; fi
).
To check that a command returns success, use if somecommand; then ...
.
To check that a command returns failure, use if ! somecommand; then ...
.
To additionally capture output with command substitution: if output=$(somecommand); then ...
This also applies to while
/until
loops.
Example of incorrect code:
make sometarget
if [ $? -ne 0 ]
then
echo "Build failed"
fi
Example of correct code:
if ! make sometarget
then
echo "Build failed"
fi
The default Solaris 10 bourne shell does not support '!' outside of the test command (if ! somecommand; then ...
returns !: not found
)