On Thu, Dec 19, 2019 at 09:47:03AM +0100, to...@tuxteam.de wrote: > So this "if" means: > > if ## if > test ## > -z "$home" ## the value of $home is empty > -o ## or > \! ## there is NOT > -d "$home" ## a directory named "$home" > ## we're homeless.
Expanding on what I said in a previous message, the reason this is not portable is because parsing this kind of expression is hard, and shells did not all agree on how to do it. So rather than try to enforce some kind of difficult parsing within test, POSIX decided to scrap the whole thing. In POSIX's wording: 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. Shells that don't support binary -o and -a are compliant by default, and shells that DO support it are simply offering an extension. BUT, this is only true for some expressions involving -o and -a. Not all expressions. What POSIX actually settled on for the test command is a strict interpretation based on the number of arguments passed. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html 0 arguments: Exit false (1). 1 argument: Exit true (0) if $1 is not null; otherwise, exit false. 2 arguments: If $1 is '!', exit true if $2 is null, false if $2 is not null. If $1 is a unary primary, exit true if the unary test is true, false if the unary test is false. Otherwise, produce unspecified results. 3 arguments: If $2 is a binary primary, perform the binary test of $1 and $3. If $1 is '!', negate the two-argument test of $2 and $3. [OB XSI]  If $1 is '(' and $3 is ')', perform the unary test of $2.  On systems that do not support the XSI option, the results are unspecified if $1 is '(' and $3 is ')'. Otherwise, produce unspecified results. 4 arguments: If $1 is '!', negate the three-argument test of $2, $3, and $4. [OB XSI]  If $1 is '(' and $4 is ')', perform the two-argument test of $2 and $3.  On systems that do not support the XSI option, the results are unspecified if $1 is '(' and $4 is ')'. Otherwise, the results are unspecified. >4 arguments: The results are unspecified. So... your binary -o and -a are only allowed as extensions in one of the "results are unspecified" cases, e.g. when there are 5 or more arguments given to test. Your code above has 6 arguments, so this is allowable, if a given shell chooses to attempt it. Bash is one of the shells that does. Still, you shouldn't be writing this type of code. If you're going to require bash extensions, just go all in and use [[ -z $v || ! -d $v ]] instead. Otherwise, string together two test commands. (Also remember that test -a is a legacy synonym for test -e, so a shell that wants to parse binary -a first has to figure out whether it's looking at a unary -a or a binary -a. Bash's [[ || ]] doesn't have that problem.) The POSIX page actually goes into a lot more detail about some of the historical glitches with test. It's worth a read. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128_16