Why isn’t [ -n ] false like [ -n “” ]?

My question is on return values produced by this code:

if [ -n ]; then echo "true"; else echo "false"; fi

This prints true.

Its complementary test using [ -z ] also prints true:

if [ -z ]; then echo "true"; else  echo "false"; fi

In the above code, why does the [ -n ] test assume the string value that is not passed at all, as not null?

The code below prints false. This is expected since the passed string value is null and of zero length.

if [ -n "" ]; then echo "true"; else  echo "false"; fi

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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

Method 2

[x] is equivalent to [ -nx] even if x starts with - provided there is no operand.

$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0

Method 3

[ -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”.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x