0

Consider the following in bash:

root@debian-lap:/tmp I=$(echo)
root@debian-lap:/tmp echo "$I"

root@debian-lap:/tmp [ -z "$I" ] && echo "TRUE" || echo "FALSE"
TRUE

This means that variable $I is zero. The same I could achieve with negation test to see if variable is non zero, and ! makes test reverse so it checks is variable zero

root@debian-lap:/tmp ! [ -n "$I" ] && echo "TRUE" || echo "FALSE"
TRUE
root@debian-lap:/tmp

So, my question is, are there any special cases when to use -z and ! -n , or vice versa ! -z and -n as they are basically doing the same test?

Thanks

  • 2
    Earlier shells, like the Bourne shell, did not have a ! reserved word for negation of expressions, so you needed both -z and -n. See differences. – meuh Jun 14 '17 at 15:48
  • Thanks guys, know its maybe dumb question, but had to ask are there some special cases of using it :) – fugitive Jun 14 '17 at 15:53
  • 1
    The only dumb questions are those left unasked, and those asked twice. – DopeGhoti Jun 14 '17 at 20:19
2

You are given -n and -z for the same reason that other test suites give you both == and !=, or AND and NOT. Some test cases can be made a lot clearer to future maintainers by eschewing double-negatives. Also, as mentioned in an above comment, ancient incarnations of sh (i. e. the Bourne and Thompson shells), as opposed to modern POSIX sh did not have a ! keyword to negate the truthiness of test expressions.

8

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))...).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.