What is the difference between these two Bash if-statements? e.g.
if [ "$FOO" = "true" ]; then
if [ $FOO = "true" ]; then
What is the difference? It seems that both statements work the same.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
If the value of
$FOO is a single word that doesn't contain a wildcard character
\[*?, then the two are identical.
$FOO is unassigned, or empty, or more than one word (i.e., contains whitespace or
$IFS), then the unquoted version is a syntax error. If it happens to be just the right sequence of words (such as
0 -eq 0 -o false), the result could be arbitrary. Therefore, it is good practice to always quote variables in shell scripts.
"true" does not need to be quoted.
To illustrate what problems it might cause, here a few examples.
Let's say we have two variables as follow:
FOO="some value" BAR="some value"
Now we have two variables holding exactly the same string/value. If we did some if statements to test the result, in your case:
if [ $FOO = "$BAR" ]; then echo "match"; else echo "no match"; fi
At this point you will get
bash: [: too many arguments. The unquoted $FOO holds now three values, namely
'[ , some , value'.
[ test keyword doesn't know what to execute because it is expecting the first or second argument to be an operator.
When we quote "$FOO" we explicitly tell
if to look at the right values where no word splitting takes place.
my_file="A random file.txt"
rm $my_filemeans removing 'A' 'random' 'file.txt' which makes it three files.
rm "$my_file"will remove "A random file.txt" which makes one file.
Hope I've not confused you with these examples.
Here, it's not that much about quoting or not in
if statements but in arguments to any command, and in that particular case, the
[ command is a command like any other (though it's builtin in most Bourne-like shells) and like any other command can be used in the
else parts of
if...fi statements as well as outside
In Bourne-like shells other than
zsh, leaving a parameter expansion unquoted is the split+glob operator.
$FOO, will be split on characters of
$IFS using complex rules and the resulting words subject to filename generation which will generate a variable number of arguments to the
[ command where it expects exactly one.
So like in any argument to any command, that
$FOO must be quoted so its contents be passed as one argument.
[ is one of those commands where it is critical not to forget to quote variables, as not doing it amounts to an arbitrary command injections in many
[ implementations (if there's a chance the contents of the variable may end up being under the control of an attacker).
That includes the
[ builtin utility of
pdksh and derivatives (and
zsh when in
ksh emulation), and the
[ standalone utility (
/usr/xpg4/bin/[...) of those systems like Solaris where it's implemented as a wrapper script around
[ implementations like all those builtin commands in those shells which under some circumstance can interpret arithmetic expressions or can operate on variable names can end up executing code.
Here, as an example, in the
bash shell (the shell of the GNU project which is also the
sh implementation of a few systems), and with the default value of
bash-5.0$ FOO='-v x[$(reboot)] -o true' bash-5.0$ if [ $FOO = "true" ]; then echo yes; fi System rebooting now! yes
Because it was not quoted and because
$IFS contains the SPC character by default,
$FOO was split into
true. Of those, only the second contains glob operators (
[...]). In my case, it didn't match any file (that would be different if there was a
xo file in the current directory for instance), so was left as is (another peculiarity of Bourne-like shells, most other shells would complain that the glob didn't match).
So that ended up asking
[ whether the
$x array was set for indice
$(reboot), and ended up running
reboot as part of the evaluation of that arithmetic expression, or (
true was equal to
true, hence the
More reading at:
In this specific case there is no difference.
$FOO contains a space or some special characters, you will have a problem.
"$FOO" case, it will use the variable in total, to make the match insulating you from the space problem.
However, if you use
$FOO and there is a special case it will affect the if statement.