1

From man bash:

-n string
    True if the length of string is non‐zero.

Examples:

# expected
$ var=""; [ -n "$var" ]; echo $?
1

# unexpected?
$ var=""; [ -n $var ]; echo $?
0

Here we see that -n with unquoted variable containing empty string returns true. Why?

Why is $var required to be quoted here?

7
  • Because $ [ -n ]; echo $? 0
    – stevea
    Commented Dec 28, 2023 at 12:08
  • @stevea, that doesn't explain much. Why would [ -n ] be relevant when they clearly had [ -n $var ]? Why would [ -n ] be true? What does it even mean?
    – ilkkachu
    Commented Dec 28, 2023 at 12:09
  • IOW -n with no argument returns true. This is not well documented. Your $var and "$var" evaluate to no-argument before /usr/bin/test is called.
    – stevea
    Commented Dec 28, 2023 at 12:09
  • 1
    @stevea, sigh... Claims like that about documentation would be much easier to accept if they came with some grounds, e.g. if you showed the piece of documentation you were reading, that didn't properly describe the behavior. See e.g. the answer under [Why isn't [ -n ] false like [ -n "" ]?](unix.stackexchange.com/q/400889/170373) (The Q I linked there).
    – ilkkachu
    Commented Dec 28, 2023 at 12:15
  • @stevea, also, "$var" will only ever result in one argument (or word/field, howevery you like), never none (nor more than one)
    – ilkkachu
    Commented Dec 28, 2023 at 12:17

1 Answer 1

4

The $ sign introduces parameter expansion, command substitution, or arithmetic expansion

In your second case ($var unquoted) since $var is empty, it will expand to nothing. Just as if you had not specified any operand to the test.

In your first case, ($var double quoted) $var will still expand to nothing but within the double quotes, this incidentally providing the empty string "" as operand to the test.


Update following additional question from OP in comments :

why doesn't -n with no operand lead to, for example, "error: -n requires an operand"?

To which I had initially answered that, according to the manual, test

Exits with a status of 0 (true) or 1 (false)

With false including the case where "an invalid argument is given".

Some comment from illkachu provides a deeper insight :

A few test implementations (including Bash's) actually do return a distinct falsy status for an error, i.e. 0 for true, 1 for false and 2 for error

However :

It's just that both 1 and 2 are falsy as far as shell conditionals are concerned

6
  • Any ideas / knowledge why doesn't -n with no operand lead to, for example, "error: -n requires an operand"? Does this question deserve to be posted as a new question?
    – pmor
    Commented Dec 28, 2023 at 11:27
  • @pmor : For reasons of coherence with bash test command I presume : See linuxcommand.org/lc3_man_pages/testh.html in particular : "Exit Status: Returns success if EXPR evaluates to true; fails if EXPR evaluates to false or an invalid argument is given."
    – MC68020
    Commented Dec 28, 2023 at 11:36
  • @pmor : In my above comment, I mean test gets a binary exit status (true exclusive-or false) not a ternary which could include some value that could be interpreted as sort of syntax error.
    – MC68020
    Commented Dec 28, 2023 at 11:57
  • 2
    @MC68020, A few test implementations (including Bash's) actually do return a distinct falsy status for an error, i.e. 0 for true, 1 for false and 2 for error. It's just that both 1 and 2 are falsy as far as shell conditionals are concerned, so one often doesn't get to see the difference. It'd need explicitly looking at the value of $?. Not that there's any invalid arguments here in this case (and anyway, [ -n ] is true), but you could try e.g. [ x x ] or similar. e.g. bash -c '[ x x ]; echo $?' prints 2.
    – ilkkachu
    Commented Dec 28, 2023 at 12:40
  • 1
    Thanks a lot @ilkkachu (since I learnt something :-) ) for that deeper insight. I updated my answer accordingly.
    – MC68020
    Commented Dec 28, 2023 at 14:53

Not the answer you're looking for? Browse other questions tagged .