sh -> vars in [ -a ] aren't evalueated correctly

Code:
# Both vars are undefined
[ ! "$DESTDIR" ] && echo "TRUE that '\$DESTDIR' doesn't exist!"
[ "$changing_kern" ] || echo "TRUE that '\$changing_kern' doesn't exist!"

echo
# NONE if statement, should echo anything !!!
    # + [ ! '' -a '' ]
    if [ ! "$DESTDIR"  -a  "$changing_kern" ]; then
        echo "If statement returned TRUE, with '-a'"
    fi

    # + [ ! '' ]
    # + [ '' ]
    if [ ! "$DESTDIR" ] && [ "$changing_kern" ]; then
        echo "If statement returned TRUE, with '&&'"
    fi
 
"Doesn't exist" is misleading, "not defined" or "not set" would be better.

Instead of just ! "$string", I would use -n to test if a string is non-zero in length, or -z to see if it's zero in length. See test(1). Also, the last if should use -a instead of &&.
 
wblock@ said:
"Doesn't exist" is misleading, "not defined" or "not set" would be better.
True.
But this is advanced, so I've thought it is implied, for those that look at the code, not what is being echoed.

wblock@ said:
Instead of just ! "$string", I would use -n to test if a string is non-zero in length, or -z to see if it's zero in length. See test(1). Also, the last if should use -a instead of &&.

Point is, that I like to use shorter sintax in order to achieve same goal, which means without -z and -n
The last if. is exactly one that works for short form!

So the question is ..., WHY does it fail in first form?!
 
According to test(1),
% [ ! \( "$DESTDIR" \) ] && echo "DESTDIR is undefined"
and that works.

This is better, IMO, being more specific about what is being tested. And it's shorter.
% [ -z "$DESTDIR" ] && echo "DESTDIR is undefined"
 
And this one is shortest and works:
# [ ! "$DESTDIR" ] && echo "DESTDIR is undefined"

So why doesn't 2 shorts work inside of a test []
 
And this one does not work:
% [ ! "$DESTDIR" -a "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"

There's a difference between what test(1) evaluates for an expression and the exit status it returns.
 
Both are undefined and I still get output:
Code:
DESTDIR is not defined, changing_kern is defined
Why did it returned true exit code here, if left side of expression was true and left one false?
 
Seeker said:
Both are undefined and I still get output:
Code:
DESTDIR is not defined, changing_kern is defined
Why did it returned true exit code here, if left side of expression was true and left one false?

Exactly, it does not work. Why? Could be one of the ambiguous cases described in test(1). It works if you rewrite it to not use -a:
% [ ! "$DESTDIR" ] && [ "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"
Or if it is rewritten to use grouping parens:
% [ \( ! "$DESTDIR" \) -a "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"

This works, and indicates what is being tested:
% [ -z "$DESTDIR" -a -n "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"
 
Seeker said:
And this one is shortest and works:
# [ ! "$DESTDIR" ] && echo "DESTDIR is undefined"

So why doesn't 2 shorts work inside of a test []

They don't necessarily do the same thing though.

If "$DESTDIR" evaluates to false, then !(FALSE) == TRUE.
You should really test for the closest possible thing. Adding a single character is not making your code substantially longer, but much clearer in its meaning.
 
wblock@ said:
Exactly, it does not work. Why? Could be one of the ambiguous cases described in test(1). It works if you rewrite it to not use -a:
% [ ! "$DESTDIR" ] && [ "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"
Or if it is rewritten to use grouping parens:
% [ \( ! "$DESTDIR" \) -a "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"

This works, and indicates what is being tested:
% [ -z "$DESTDIR" -a -n "$changing_kern" ] && echo "DESTDIR is not defined, changing_kern is defined"
Well, as a goal to achieve shortest syntax, grouping parentheses are totally out of game.
If -a and -o are ambiguous and there is no panacea, then I'll replace them with:
... ] && [ ... and ... ] || [ ... respectively

mix_room said:
They don't necessarily do the same thing though.

If "$DESTDIR" evaluates to false, then !(FALSE) == TRUE.
You should really test for the closest possible thing. Adding a single character is not making your code substantially longer, but much clearer in its meaning.
I don't understand, what you wanted to say:
Making DESTDIR var false, FALSE or False, will never echo anything, for:
Code:
[ ! "$DESTDIR" ] && echo "DESTDIR is undefined"
 
I recommend not using -a, -o and parentheses at all, but the construct
Code:
[ ! "$string1" -a "$string2" ]
is particularly nasty. Some test implementations such as the builtins in bash and FreeBSD sh consider -a and -o "binary primaries" (POSIX SUSv4 XCU 4 Utilities test) and obey the rule for 4 arguments that if the first is '!' the result is the negation of the 3-argument test on the remaining arguments, determined by the binary primary -a.

This really does not make much sense (!, -a and -o are really more like "operators" than "primaries") but I think it is what the standard says.

In any case, if you use -a and -o, you will find more nasty surprises because some expressions containing them are ambiguous, so I suggest not using them.
 
Yes. And here is another argument for use of:
... ] && [ ... and ... ] || [ ...

test(1)
BUGS
Both sides are always evaluated in -a and -o. For instance, the writable
status of file will be tested by the following command even though the
former expression indicated false, which results in a gratuitous access
to the file system:
[ -z abc -a -w file ]
To avoid this, write
[ -z abc ] && [ -w file ]
 
Back
Top