user1011471
user1011471

Reputation: 1130

Do test operators -a and -o short circuit?

Do test operators -a and -o short circuit?

I tried if [ 0 -eq 1 -a "" -eq 0 ]; then ... which complained about the syntax of the second conditional. But I can't tell if that's because

  1. -a does not short circuit
  2. or test wants everything properly formatted before it begins and it still short circuits.

The result is leading me to create a nested if when really what I wanted was a situation where the first conditional would guard against executing the second if a particular var had not yet been set...

edit: As for why am I using obsolescent operators, the code has to work everywhere in my environment and I just found a machine where

while [ -L "$file" ] && [ "$n" -lt 10 ] && [ "$m" -eq 0 ]; do

is an infinite loop and changing to the obsolete -a yields good behavior:

while [ -L "$file" -a "$n" -lt 10 -a "$m" -eq 0 ]; do

What should I do? The first expression works on many machines but not this machine which appears to require the second expression instead...

Upvotes: 10

Views: 1083

Answers (2)

Karoly Horvath
Karoly Horvath

Reputation: 96276

Well, you already know the behaviour, so this question is really about how to interpret those results. But TBH, there aren't many real word scenarios where you'll observe different behaviour.

I created a small test case to check what's going on (at least, on my system, since the other answer suggests it's not standardized):

strace bash -c "if [ 0 -eq 1 -a -e "/nosuchfile" ]; then echo X; fi"

If you check the output you'll see that bash looks for the file, so the answer is:

The operators don't short circuit.

Upvotes: 2

Charles Duffy
Charles Duffy

Reputation: 295679

Per the POSIX specification for test:

>4 arguments: The results are unspecified.

Thus, barring XSI extensions, POSIX says nothing about how this behaves.

Moreover, even on a system with XSI extensions:

expression1 -a expression2: True if both expression1 and expression2 are true; otherwise, false. The -a binary primary is left associative. It has a higher precedence than -o. [Option End]

expression1 -o expression2: True if either expression1 or expression2 is true; otherwise, false. The -o binary primary is left associative. [Option End]

There's no specification with respect to short-circuiting.


If you want short-circuiting behavior -- or POSIX-defined behavior at all -- use && and || to connect multiple, separate test invocations.


Quoting again, from later in the document:

APPLICATION USAGE

The XSI extensions specifying the -a and -o binary primaries and the '(' and ')' operators have been marked obsolescent. (Many expressions using them are ambiguously defined by the grammar depending on the specific expressions being evaluated.) Scripts using these expressions should be converted to the forms given below. Even though many implementations will continue to support these obsolescent forms, scripts should be extremely careful when dealing with user-supplied input that could be confused with these and other primaries and operators. Unless the application developer knows all the cases that produce input to the script, invocations like:

test "$1" -a "$2"

should be written as:

test "$1" && test "$2"

Upvotes: 5

Related Questions