Once upon a time, lejeczek peljasz@yahoo.co.uk said:
There is a several ways to run tests in shell, but 'test' which is own binary as I understand, defeats me.. in those three examples - regardless of how one can "bend" quoting & expanding - the same identical variable syntax is used and yet different tests render the same result.
It's because shell variable expansion happens before the command is run. When you do:
unset _Val; test -z ${_Val}
The shell expands ${_Val} to nothing, then does whitespace removal, and runs test with a single argument, "-z". When instead you do:
unset _Val; test -z "${_Val}"
The shell sees the quoted string and keeps it as an empty argument, so test gets run with two arguments: "-z", and "" (null aka a zero-length string).
It appears that test treats -z/-n (and other tests) with no following argument as always successful, rather than an error. Checking the POSIX/Single Unix Specification standard, this is compliant; it says that any time test is run with one argument, the exit is true (0) if the argument is not null, false otherwise (e.g. test "" is false, while test -blob is true).
Note that bash has test and [ as shell builtins, but the external command /usr/bin/test and /usr/bin/[ have the same behavior.
The [[ ]] method is a bash extension, and treats a test operator without a corresponding operand (e.g. [[ -z ]]) as an error condition instead of returning true.