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?

MC68020
  • 7,981
pmor
  • 599
  • Because $ [ -n ]; echo $? 0 – stevea Dec 28 '23 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 Dec 28 '23 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 Dec 28 '23 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 "" ]? (The Q I linked there). – ilkkachu Dec 28 '23 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 Dec 28 '23 at 12:17
  • Sigh, do you need a pointer to the man pages ? "man bash" states only "-n string True if the length of string is non-zero.". It does NOT state behavior when the 'string' argument is zero-length, is a non-string, or is absent; therefore the documentation is clearly defective. – stevea Jan 01 '24 at 01:24
  • @ikkachu states: <<also, "$var" will only ever result in one argument (or word/field, howevery you like), never none (nor more than one) – ilkkachu>>, but this is blatantly false. Try "${!B@}" . Bash expansion is complex, with many exceptions, and marginally documented, leading to Ikkachu's understandable error. – stevea Jan 01 '24 at 20:21

1 Answers1

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

MC68020
  • 7,981
  • 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 Dec 28 '23 at 11:27
  • @pmor : For reasons of coherence with bash test command I presume : See https://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 Dec 28 '23 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 Dec 28 '23 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 Dec 28 '23 at 12:40
  • 1
    Thanks a lot @ilkkachu (since I learnt something :-) ) for that deeper insight. I updated my answer accordingly. – MC68020 Dec 28 '23 at 14:53
  • Hence, "no argument" is not an "invalid argument". What's the rationale for [ -n ] to return 0 instead of non-zero? In other words: why the string is non-empty if there is no string? See also: https://en.m.wikipedia.org/wiki/Vacuous_truth . – pmor Dec 28 '23 at 19:15