This $?
refers to a condition, not a command. Assign to a variable to avoid it being overwritten.
Problematic code:
mycommand
if [ $? -ne 0 ] && [ $? -ne 14 ]
then
echo "Command failed"
fi
or
mycommand
[ $? -gt 0 ] && exit $?
Correct code:
mycommand
ret=$?
if [ $ret -ne 0 ] && [ $ret -ne 14 ]
then
echo "Command failed"
fi
or
mycommand || exit $?
Rationale:
ShellCheck found a $?
that always refers to a condition like [ .. ]
, [[ .. ]]
, or test
.
This most commonly happens when trying to inspect $?
before doing something with it, such as inspecting it again or exiting with it, without realizing that any such inspection will also overwrite $?
.
In the first problematic example, [ $? -ne 14 ]
will never be true because it only runs after [ $? -ne 0 ]
has modified ? to be 0. The solution is to assign `
?from
mycommand` to a variable so that the variable can be inspected repeatedly.
In the second problematic example, exit $?
will always exit 0
, because it only runs if [ $? -gt 0 ]
returns success and sets $?
to 0. The solution could again be to assign $?
to a variable first, or (as shown) use mycommand || exit $?
as there is no condition to overwrite $?
.
Exceptions:
None. Note that ShellCheck does not warn if the usage of $?
after [ .. ]
is unconditional, as in [ -d dir ]; return $?
.
Related resources:
- Help by adding links to BashFAQ, StackOverflow, man pages, POSIX, etc!