Why do [[ -z ]] and [[ -v ]] have different syntax?
Test operators -v
and -z
are just not the same.
Operator -z
tells if a string is empty. So it is true that [[ -z "$a" ]]
will give a good approximation of "variable a
is unset",
but not a perfect one:
the expression will yield true if
a
is set to the empty string rather than unset;the enclosing script will fail if
a
is unset and the optionnounset
is enabled.
On the other hand, -v a
will be exactly "variable a
is set", even
in edge cases. It should be clear that passing $a
rather than a
to
-v
would not be right, as it would expand that possibly-unset
variable before the test operator sees it; so it has to be part of
that operator's task to inspect that variable, pointed to by its name,
and tell whether it is set.
There's a difference in the meaning of -z
and -v
:
echo Empty:
x="" # Same with x=
[[ -z $x ]] && echo z
[[ -v x ]] && echo v
unset x
echo Unset
[[ -z $x ]] && echo z
[[ -v x ]] && echo v
By using -z
, you can't distinguish a variable that was assigned an empty value from a variable that hasn't been assigned any value.
Also, [[ -z $x ]]
is still sensible to set -u
, while [[ -v x ]]
isn't.