5

I am working on a shell script and decided to check my work via shellcheck.net. I am able to get functionally the same behavior of the following two lines in my script:

findmnt /dev/sda1 >/dev/null ; if [ $? -eq 0 ]; then echo 1; else echo 0; fi

vs.

if ! findmnt /dev/sda1 >/dev/null; then echo 0; else echo 1; fi

However shellcheck throws:

SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.

It is not immediately clear to me which to use. I do see: https://github.com/koalaman/shellcheck/issues/1167 which seems to have amended this for several possible values. I want to be sure that I am writing something that uses best practices and will run without issue and report accurately.

3
  • github.com/koalaman/shellcheck/wiki/SC2181 has a rationale for the warning. What kind of answer are you expecting here, other than repeating that rationale? Sep 28, 2021 at 18:59
  • 1
    if findmnt /dev/sda1 >/dev/null; then echo 1; else echo 0; fi would be a more direct equal of the first one. Using ! there flips the sense of the test.
    – ilkkachu
    Sep 28, 2021 at 19:33
  • Echoing what looks like a exit code is an indication that something else should also be looking at the exit code of findmnt.
    – chepner
    Sep 29, 2021 at 15:02

1 Answer 1

10

You only need to use the special variable $? when you need its value across several invocations of other utilities. For example, you may want to output it in a diagnostic message and then return it from a function. Outputting something with printf would reset $? to the exit-status of printf, so you wouldn't be able to do return "$?" (or return) directly afterward to return the original exit-status. Notice that even testing something with [ ... ] resets $?. You would probably instead assign $? to some other variable and use that.

You might want to consider using $? in an if statement if that is the style used in the rest of the project. In that case, remember to quote the expansion, as technically, $IFS might contain digits, which means the unquoted expansion of $? would potentially disappear entirely or partially.

utility

# shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
    echo ok
else
    echo fail
fi

However, this makes for much typing and makes the code slightly obfuscated and a bit unnecessarily tricky to follow. Note that the invocation of utility above is not connected to the if statement following it in any immediate way.

There is additionally a bit of extra redundancy here since the if statement is now examining the exit-status of the [ utility to test whether a variable is zero or not. The variable is the exit-status of another utility, which we could have used with if directly.

if utility; then
    echo ok
else
    echo fail
fi

Here it's clear that the invocation of utility is an integral part of the if statement.

See also the rationale behind the SC2181 warning in the ShellCheck wiki.

3
  • Thanks, I think I was trying to get another opinion or idea of what is considered best practices/best form. shellcheck is a great tool, but it's sometimes important for me to read or see other opinions on the matter outside of the tool's maintainers.
    – Kahn
    Sep 28, 2021 at 19:19
  • Note that something like foo; ret=$?; if [ "$ret" = 0 ]; then ....; elif [ "$ret" = 1 ]; then ...; fi also requires both the explicit test on the exit status (since if cmd... can only test for zero vs. non-zero) and requires the temporary variable, since the [ ... ] tests also affect $? themselves.
    – ilkkachu
    Sep 28, 2021 at 19:35
  • 1
    You would also use $? directly if you care about the actual value, not just the zero/non-zero distinction that the if statement makes. case $? in ... is good for this.
    – chepner
    Sep 29, 2021 at 15:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .