Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

The title says it all: When I execute the following line

test -n && echo not empty

it prints "not empty". This occurs when you have an empty variable, and test for non-emptyness while forgetting to quote the value:

VAR=
test -n  $VAR  && echo wrong 1
test -n "$VAR" && echo wrong 2

Is this expected behaviour?

share|improve this question
add comment

5 Answers

up vote 9 down vote accepted

Yes, this is expected behaviour. When only one argument is passed to test, a length check is performed. From man bash:

test and [ evaluate conditional expressions using a set of rules based on the number of arguments.

0 arguments: The expression is false.

1 argument: The expression is true if and only if the argument is not null.

That is, essentially it is the equivalent of test foo, but using -n as the string.

share|improve this answer
add comment

test -n is prima facie malformed, since -n requires an argument. I believe some historical implementations treated it as a syntax error (and returned a nonzero status). However, in all the shells you're likely to encounter in the 21st century, the behavior is well-defined (by POSIX, following existing practice): if test has only one argument, then it is true if and only if that argument is non-empty.

Note that if you leave out the quotes, the test may end up being false for some non-empty values of $VAR. It can even print out an error message if there are globbing characters in $VAR.

VAR='foo -a -z bar'; test -n $VAR || echo "true... and false is false"
VAR='= n-'; test -n $VAR || echo "this is an equality test"
VAR='*'; test -n $VAR || echo "you may or may not see this depending on what files are in the current directory"

test -z $VAR is similarly broken.

Ksh, bash and zsh have a [[ … ]] conditional construct which imitates the traditional test and [ utilities. Unlike [, which either is an external utility or is a built-in that is parsed like one, [[ … ]] is part of the shell syntax. There is no word splitting or globbing inside [[ … ]]. [[ -n $VAR ]] is fine (as long as you don't care that your scripts won't run under other shells such as ash).

share|improve this answer
add comment

Check also [[ ... ]], which does not suffer this behaviour:

[[ -n $VAR ]] && echo wrong 3
[[ -n "$VAR" ]] && echo wrong 4
share|improve this answer
    
Interesting and worth being aware of, but "suffer" is probably not the right word here... [[ ... ]] is not the same as [ ... ] which does exhibit the same behaviour as test and is the function referred to in man bash... Within [[ ... ]] variable do not need to be "$quoted" to be recognized a variable (ie. as an arg to [[ ) ... This boils down to a simple case of: the variable was not quoted and it should have been. –  Peter.O Jan 27 '12 at 14:32
add comment

Since the bash buildin test, and /usr/bin/test lead to the same result, I say yes, it is expected behaviour.

share|improve this answer
add comment

It seems when you do the following:

VAR=
test -n $VAR && echo helloworld

It's treating it as though the argument is not there:

test -n && echo helloworld

And, for some reason, when the argument is not supplied, it always runs the command afterwards (i.e. it displays helloworld). I tried this on another unuary operator and it did the same thing:

FILENAME=
test -f $FILENAME && echo helloworld

I think if you want to have expected behavior you must quote the argument:

VAR=
test -n "$VAR" && echo helloworld
FILE=
test -f "$FILE" && echo helloworld

The above yields no message echoing to the screen.

As to is that expected behavior? I can't find it in the documentation anywhere, but, it seems fairly reproducible and consistent.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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