I've read that you need double quotes for expanding variables, e.g.
if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi
will work as expected, while
if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi
will always say $test ok
even if $test
is null.
but then why don't we need quotes in echo $test
?
Best Answer
You always need quotes around variables in all list contexts, that is everywhere the variable may be expanded to multiple values unless you do want the 3 side effects of leaving a variable unquoted.
list contexts include arguments to simple commands like
[
orecho
, thefor i in <here>
, assignments to arrays... There are other contexts where variables also need to be quoted. Best is to always quote variables unless you've got a very good reason not to.Think of the absence of quotes (in list contexts) as the split+glob operator.
As if
echo $test
wasecho glob(split("$test"))
.The shell behaviour is confusing to most people because in most other languages, you put quotes around fixed strings, like
puts("foo")
, and not around variables (likeputs(var)
) while in shell it's the other way round: everything is string in shell, so putting quotes around everything would be cumbersome, youecho test
, you don't need to"echo" "test"
. In shell, quotes are used for something else: prevent some special meaning of some characters and/or affect the behaviour of some expansions.In
[ -n $test ]
orecho $test
, the shell will split$test
(on blanks by default), and then perform filename generation (expand all the*
, '?'... patterns to the list of matching files), and then pass that list of arguments to the[
orecho
commands.Again, think of it as
"[" "-n" glob(split("$test")) "]"
. If$test
is empty or contains only blanks (spc, tab, nl), then the split+glob operator will return an empty list, so the[ -n $test ]
will be"[" "-n" "]"
, which is a test to check wheter "-n" is the empty string or not. But imagine what would have happened if$test
was "*" or "= foo"...In
[ -n "$test" ]
,[
is passed the four arguments"["
,"-n"
,""
and"]"
(without the quotes), which is what we want.Whether it's
echo
or[
makes no difference, it's just thatecho
outputs the same thing whether it's passed an empty argument or no argument at all.See also this answer to a similar question for more details on the
[
command and the[[...]]
construct.