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.

  • In Bash, use double square brackets and you don't need the quotes and you get additional benefits. Aug 14 '13 at 11:11
  • @DennisWilliamson Not quite, you do need quotes on the right-hand side of the (in)equality and pattern matching operators. Aug 14 '13 at 22:41
  • @Gilles: Sometimes not. For literal strings containing spaces or for literal strings or variables that contain glob characters that you want to be taken literally, the right side must be quoted: a='foo bar'; [[ $a == "foo bar" ]]. However, a variable which does not contain glob characters need not be: [[ $a == $a ]]. Word expansion is not performed inside double square brackets. And for regex matching, the pattern on the right hand side must not be quoted or it will be taken as literal string: [[ $a =~ .*oo.*r ]] (the pattern should be in an un-quoted variable, however, instead ... Aug 15 '13 at 1:14
  • of being incorporated literally as here). For glob-style pattern matching, the glob characters must not be quoted, whether literal or in a variable: [[ $a == foo* ]]. Can you provide any additional examples of a requirement for quoting besides my literal string example? Aug 15 '13 at 1:14

If the value of $FOO is a single word that doesn't contain a wildcard character \[*?, then the two are identical.

If $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.

Incidentally, "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.

Another example:

my_file="A random file.txt"
  • doing rm $my_file means removing 'A' 'random' 'file.txt' which makes it three files.
  • doing 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.

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 if, then, elif, else parts of if...fi statements as well as outside if...fi statements.

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 bash, ksh88, ksh93, pdksh and derivatives (and zsh when in sh/ksh emulation), and the [ standalone utility (/bin/[, /usr/xpg4/bin/[...) of those systems like Solaris where it's implemented as a wrapper script around ksh's builtin [.

Those [ 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 $IFS:

bash-5.0$ FOO='-v x[$(reboot)] -o true'
bash-5.0$ if [ $FOO = "true" ]; then echo yes; fi
System rebooting now!

Because it was not quoted and because $IFS contains the SPC character by default, $FOO was split into -v, x[$(reboot)], -o and 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 (-o) whether true was equal to true, hence the yes output.

More reading at:


In this specific case there is no difference.

However, if $FOO contains a space or some special characters, you will have a problem.

In the "$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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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