I want to test if a parameter is an empty string "".
When the parameter is not set, the test should fail.
Why does the following not succeed?
$ unset aa $ if [ ${aa}=="" ]; then echo yes; else echo no; fi yesWhat shall I do instead?
I want to test if a parameter is an empty string "".
When the parameter is not set, the test should fail.
Why does the following not succeed?
$ unset aa
$ if [ ${aa}=="" ]; then echo yes; else echo no; fi
yes
What shall I do instead?
Your (attempted) test $aa == "" is equivalent of comparing two empty strings with each other, which results in a true result. This is because the shell will expand unset variables to the empty string. Without the spaces around the ==, the test will always be true as it's the same as testing on the two character string ==. This string is always true.
Instead, in bash:
$ unset aa
$ if [ -v aa ]; then echo Set; else echo Not set; fi
Not set
$ aa=""
$ if [ -v aa ]; then echo Set; else echo Not set; fi
Set
The full test for an empty string would therefore be
if [ -v aa ] && [ -z "$aa" ]; then
echo Set but empty
fi
From help test in bash:
-v VARTrue if the shell variableVARis set.
Or, from the bash manual's "CONDITIONAL EXPRESSIONS" section:
-v varnameTrue if the shell variable
varnameis set (has been assigned a value).
With the -v test, you test on the variable's name rather than on its value.
If you really want to do a string comparisson, you could do something like
if [[ "${aa-InvalidValue}" != "InvalidValue" ]] && [ -z "$aa" ]; then
echo Set but empty
fi
The expansion ${variable-value} will expand to value if variable is unset.
Note that the very similar ${variable:-value} will expand to value if variable is unset or null (the empty string).
test, i.e. [, needs whitespace around the operators, basically because otherwise foo== would be taken as containing an operator, even though it's a valid string. The [[ .. ]] construct works the same in this. (See this question and BashFAQ 031 for the [ vs [[ difference.)
So, [ ${aa}=="" ] will always be true, since [ string ] is the same as [ -n string ], i.e. it tests that the string is not empty. And here the string contains at least ==.
Then [ ${aa} == "" ] will be an error if aa is unset or empty, since an empty variable expanded without quotes disappears and [ == foo ] isn't a valid test. If aa has a nonempty value, it's false. ([[ ${aa} == "" ]] would work even without the quotes, since [[ .. ]] is special.)
Of course [ "${aa}" == "" ] would test that aa is either unset or empty, the same as [ -z "${aa}" ].
To test that it's both set, and empty, we could use [ "${aa+x}" ] && [ -z "$aa" ], or a nifty combination of those, stolen from an answer by @Stéphane Chazelas:
if [ "${aa+x$aa}" = "x" ] ; then
echo "aa is empty but set"
fi
(that works since if aa is unset, the + expansion expands to the empty string, and if it's set, it expands to x$aa, which is just x if aa is empty.)
$ foo() { [ "${1+x$1}" = "x" ] && echo "set but empty" || echo "unset or non-empty"; }
$ foo; foo ""; foo bar
unset or non-empty
set but empty
unset or non-empty
First, And I assume you do know, the == require spaces around it. The use of == is valid only in bash, ksh and zsh, better use =. Also, the variables expanded inside a test should be quoted. So, I'll assume that the line is actually:
unset aa ; if [ "${aa}" = "" ]; then echo yes; else echo no; fi
With that, your questions:
Because the expansion of a plain unset var is identical to the expansion of a plain variable set to null (from what test '[' could do).
I mean, "$aa" is the same value for both an unset aa or a null aa.
To show how that works, try this script (note that the script is sh, it works the same in dash, bash, ksh and/or zsh):
#!/bin/sh
blanktest(){
if [ "${aa}" = "" ]; then echo "$1 yes"; else echo "$1 no"; fi
}
unset aa; blanktest unset
unset aa; aa=""; blanktest blank
unset aa; aa="e"; blanktest value
Which, on execution will yield:
$ ./script
unset yes
blank yes
value no
Use a parameter expansion called "Use Alternative Value." :
${aa+x}
which will yield an x if the variable is set (either null or value) and a null if the variable is unset.
Use this test instead:
[ "x${aa}x" = "x${aa+x}" ] && echo yes || echo no
Testing script (again, sh compatible):
#!/bin/sh
blanktest(){
if [ "x${aa}x" = "x${aa+x}" ]; then echo "$1 yes"; else echo "$1 no"; fi
}
unset aa; blanktest unset
unset aa; aa=""; blanktest blank
unset aa; aa="e"; blanktest value
On execution, will print this:
$ ./script
unset no
blank yes
value no
There are several possible variations, if you are interested.