Suppose that you are writing a Bash script (specifically Bash) and that you want to get a number from a command that may fail and might also return output '0' (which is a bad value here). No problem, you say, you can write this like so:
sz=$(zpool list -Hp -o size $pool) if [ $? -ne 0 -o "$sz" -eq 0 ]; then echo failure .... fi
Because you are a smart person, you test that this does the right thing when it fails. Lo and behold:
$ ./scrpt badarg ./scrpt: line 3: [: : integer expression expected
At one level, this is a 'well of course';
-eq
specifically requires numbers on both sides, and when the command fails it does not output a number (in fact
$sz
winds up empty). At another level it is very annoying, because what we want here is the common short-circuiting logical operators.
The reason we're not getting the behavior we want is that
test
(in the built in form in Bash) is parsing and validating its entire set of arguments before it starts determining the boolean values of the overall expression. This is not necessarily a bad idea ( and
test
has a bunch of smart argument processing ), but it is inconvenient.
(Note that Bash doesn't claim that
test
's
-a
and
-o
operators are short-circuiting operators. In fact the idea is relatively meaningless in the context of
test
, since there's relatively little to short-circuit. A quick test suggests that at least some versions of Bash check every condition, eg
stat()
files, even when they could skip some.)
My brute force way around this was:
if [ $? -ne 0 -o -z "$sz" ] || [ "$sz" -eq 0 ]; then .... fi
After all,
[
is sort of just another program, so it's perfectly valid to chain
[
invocations together with the shell's actual short circuiting logical operators. This way the second
[
doesn't even get run if
$sz
looks bad, so it can't complain about 'integer expression expected'.
(This may not be the right way to do it. I just felt like using brute force at the time.)
PS: Given that Bash emits this error message whether you like it or not, it would be nice if it had a
test
operator for 'this thing is actually a number'. My current check here is a bit of a hack, as it assumes
zpool
emits either a number or nothing.
(Updated: minor wording clarification due to reddit , because they're right, 'return 0' is the wrong way to phrase that; I knew what I meant but I can't expect other people to.)