Why isn't [ -n ] false like [ -n "" ]?
[ -n ]
does not use the -n
test.
The -n
in [ -n ]
is not a test at all. When there is only one argument between [
and ]
, that argument is a string that is tested to see if it is empty. Even when that string has a leading -
, it is still interpreted as an operand, not a test. Since the string -n
is not empty--it contains two characters, -
and n
, not zero characters--[ -n ]
evaluates to true.
As Ignacio Vazquez-Abrams says, where string
is a single argument, the test performed on string
in [ string ]
is the same as the test performed on it by [ -n string ]
. When string
happens to be -n
, nothing special happens. The -n
in [ -n ]
and the second -n
in [ -n -n ]
are simply strings being tested for emptiness.
When there is only one argument between [
and ]
, that argument is always a string to be tested for nonemptiness, even if it happens to be named the same as a test. Similarly, when there are two arguments between [
and ]
and the first of them is -n
, the second one is always a string to be tested for nonemptiness, even if it happens to be named the same as a test. This is simply because the syntax for [
insists that a single argument between [
and ]
or after -n
is a string operand.
For the same reason that [ -n ]
doesn't use the -n
test, [ -z ]
doesn't use the -z
test.
You can learn more about [
in bash
by examining the help for it. Notice that is a shell builtin:
$ type [
[ is a shell builtin
Thus you can run help [
to get help on it:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
For more information, including what tests are supported and how they work, you will have to see the help on test
. When you run the command help test
, you'll get a detailed list. Rather than reproduce it all, here's the part about string operators:
-z STRING True if string is empty.
-n STRING
STRING True if string is not empty.
STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.
Notice that -n STRING
and just STRING
do the same thing: they test if the string STRING
is not empty.
[
x]
is equivalent to [ -n
x]
even if x starts with -
provided there is no operand.
$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0
[ -n ]
is true because the [
command (aka the test
command) acts upon the number of arguments it is given. If it is given only a single argument, the result is "true" if the argument is a non-empty string. "-n" is a string with 2 characters, not empty, therefore "true".