1. [ -z "$var" ]
2. [ ! -n "$var" ]
3. ! [ -n "$var" ]
4. [ ! "$var" ]
5. [ "$var" = '' ]
6. [ ! "$var" != '' ]
7. [ '' = "$var" ]
...²
Are all functionally equivalent in POSIX shells¹. The Bourne shell¹ didn't have the !
keyword, so wouldn't support 3 above and had all sorts of bugs with special values of $var
(like =
, -n
, !
...) in all but 7 (many other shells also had similar bugs).
In a similar vein, you can (and should) use [ "$a" = "$b" ] && [ "$x" = "$y" ]
in place of [ "$a" = "$b" -a "$x" = "$y" ]
, the latter being deprecated and non-reliable.
The !
of 3 is a POSIX shell feature. It still makes sense of the test
/[
utility to support its own !
operator (as in 2/6) for other shells or non-shell applications that may want to use it and negate conditions.
The test
utility was introduced by Unix v7. Before that, there was a if
utility that had !
, =
, !=
, -a
/-o
, but no -n
/-z
.
I suppose -n
/-z
were added for convenience (test -n "$var"
being a short form for test "$var" != ''
and -z
being added for consistency)
¹ Technically, while test
/[
is built in virtually all Bourne-like shells, that's not mandated by POSIX and early versions of the Bourne shell didn't have it built-in. While the Almquist shell always had a test
builtin, some BSDs did not enable it so some BSDs did not have a [
/test
built in sh
until the 2000s. In any case, regardless of whether a particular shell has a [
/test
command built-in, all POSIX systems will also have a [
/test
command on the file system (which may or may not behave the same as the [
/test
builtin command of any shell on the system).
² That's not to say that's the only commands that can be used to test if a variable is the empty string.
case $var in
"") ...
esac
is one way that doesn't involve running any command.
expr "x$var" : 'x$' > /dev/null
${var:+"false"}
awk 'BEGIN{exit(ARGV[1] != "")}' "$var"
[ "${#var}" -eq 0 ]
Are more examples of convoluted ways to do that.
Some Korn-like shells like bash
also have some built-in conditional and arithmetic constructs that aim at replacing the [
command ([[ -z $var ]]
, ((${#var} == 0))
...).
!
reserved word for negation of expressions, so you needed both -z and -n. See differences.