I see here that testing whether $? is zero (success) or something else (failure) is an anti-pattern, but I have not been able to find this anywhere else.
Sticking to the definition of anti-pattern of the Wikipedia: "An anti-pattern (or anti-pattern) is a common response to a recurring problem that is usually ineffective and risks being highly counterproductive." Why would this be an anti-pattern?
In an organization, there are three main opportunities to identify anti-patterns: During design reviews, during code reviews and during refactoring of legacy code. Design reviews are a great opportunity to find anti-patterns.
$ echo $? If a command succeeded successfully, the return value will be 0. If the return value is otherwise, then it didn't run as it's supposed to. Let's test it out.
This is an antipattern because it introduces complexity that wouldn't exist if you didn't require the exit status to be recorded at all.
if your_command; then ...
has much less to go wrong than
your_command
if [ "$?" -eq 0 ]; then ...
For examples of things that can go wrong: Think about traps, or even new echo
statements added for debugging, modifying $?
. It's not visually obvious to a reader that a separate line running your_command
can't have anything added below it without changing logical flow.
That is:
your_command
echo "Finished running your_command" >&2
if [ "$?" -eq 0 ]; then ...
...is checking the echo, not the actual command.
Thus, in cases where you really do need to deal with exit status in a manner more granular than immediately branching on whether its value is zero, you should collect it on the same line:
# whitelisting a nonzero value for an example of when "if your_command" won't do.
your_command; your_command_retval=$?
echo "Finished running your_command" >&2 ## now, adding more logging won't break the logic.
case $your_command_retval in
0|2) echo "your_command exited in an acceptable way" >&2;;
*) echo "your_command exited in an unacceptable way" >&2;;
esac
Finally: If you enclose your_command
inside of an if
statement, this marks it as tested, such that your shell won't consider a nonzero exit status for purposes of set -e
or an ERR
trap.
Thus:
set -e
your_command
if [ "$?" -eq 0 ]; then ...
...will never (barring a number of corner cases and caveats which plague set -e
's behavior) reach the if
statement with any value of $?
other than 0
, as the set -e
will force an exit in that case. By contrast:
set -e
if your_command; then ...
...marks the exit status of your_command
as tested, and so does not consider it cause to force the script to exit per set -e
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With