23

Let's say we have 2 integers in a bash script:

value1=5
value2=3

Then why do we need to use double quotes in case of a test ? For example:

if [[ "$value1" -eq "$value2" ]]

Why not just use the following ?

if [[ $value1 -eq $value2 ]]

To me, the double quotes don't make any sense.

  • 5
    Quoting in the shell has little to do with strings (as in data types.) It's really about preventing the shell from performing word splitting (and other kinds of expansions.) – filbranden Feb 15 at 12:27
  • 13
    While, as terdon pointed out, it is not necessary too quote variables in this specific construct (and, of course, with one-word-values anywhere), I'd like to give the advice to always quote your vars. Do you really know in wich contexts you can leave variables unquoted? The reason to quote at all, even if it's not necessary with 5 and 3, is maintainability. The values may change later, and the resulting errors may not be obvious. – Peter - Reinstate Monica Feb 15 at 13:15
  • 2
    @sudodus I don't think that's true for [[ ]], only for [ ]. – Benjamin W. Feb 15 at 20:25
  • 1
    You are right, @BenjaminW. Word splitting is not the only case why it is a good idea to use double quotes for variables. There is also the case when a variable is blank. That will make the statement in [ ] fail (for example [ 2 -eq ] with an error, but [[ ]] is not vulnerable (like the case with word splitting). – sudodus Feb 15 at 20:32
  • 2
    @marcelm, Bash, ksh and Zsh have integer variables, and within [[ ]] they also coerce the operands of -eq to integers. – ilkkachu Feb 15 at 23:01
7

Word splitting.

This example is very improbable, but possible, so if you want to code defensively, cover your tracks with quotes:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

OK, all good so far. Let's throw the wrench into the gears:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Oops.

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ahh.

  • 2
    But OP uses double brackets, so no word splitting takes place. – user000001 Feb 15 at 16:22
  • 5
    Yes, this isn't really relevant to bash's [[ ]] construct. – terdon Feb 15 at 16:34
  • 1
    Eh? [ $value1 -eq $value2 ] with an empty value1 would be '[' -eq 3 ']' with no '' on the left-hand side. – Charles Duffy Feb 16 at 19:19
  • I was surprised too, but there's the evidence. – glenn jackman Feb 16 at 20:59
  • 1
    This answer does not directly relate to the question. I'm surprised it was accepted. Setting as community wiki. – glenn jackman Feb 20 at 20:23
35

You don't actually need the quotes here. This is one of the very few cases where it is safe to use a variable unquoted. You can confirm this with set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

As you can see above, the quoted and unquoted versions of the test are resolved to the exact same thing by bash. The same should be true for zsh and, I think, any other shell that supports the [[ ]] operator.

Note that this is not the case with the more portable [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

The [ ] construct, unlike the [[ ]] one, does require quoting.


Some useful links to learn more about when and why quoting is required:

  • In this case with integer variables it would be better to declare them as such. declare -i var1= is 0 when evaluated. – Freddy Feb 15 at 10:52
  • 4
    Note that -eq is arithmetic comparison, so you can even leave the $ out (in [[ .. ]]), and write [[ a -eq b ]]. With string comparison, you need the $, of course, so [[ $a = $b ]] – ilkkachu Feb 15 at 13:05
  • 2
    @user000001 good point. Although, of course, it's very possible that you want those expanded. For example, I would expect this to be a match: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. If you want to use the glob characters without their acting as a glob in a globbing context (such as the [[ ]]) then you need to quote, yes. – terdon Feb 15 at 14:51
  • 3
    @ilkkachu, that surprises me. I thought that "bare" variables would only be considered within an array subscript or ((...)) or $((...). It appears to work, but (old grumpy man, enable) I don't like it. – glenn jackman Feb 15 at 16:11
  • 1
    @glennjackman, well, sorry to be the one to tell you that, but yeah, the operands to -eq and friends inside [[ ]] are arithmetic contexts, too. :) (Related: Automatic variable expansion inside bash [[ ]] command) – ilkkachu Feb 15 at 16:32
17

Even though the double quotes aren't necessary, reasons to use them are:

  • Good practice/habit: In this case they aren't necessary, but in general double quotes are to avoid unintended word splitting.
  • Because value1 and value2 are variable, and you might not know what they contain. Otherwise you might as well ask, "Why bother with variables instead of checking if [[ 5 -eq 3 ]]? Or taking it further, why bother with the if at all when you already know that 5 isn't equal to 3? It's often better to be defensive. (It's true that word-splitting won't happen in [[, but cases where word-splitting does not happen are rare. Again, see the first point.)
1

Not directly related to your question, but I use

if (( $value1 == $value2 )); then

when I compare numbers but there you also don't have to use quotes.

  • 2
    if (( value1 == value2 )); then. In arithmetic contexts, you don't even need the $. This question, however, seems to focus on variables used within [[ ... ]] tests. – Kusalananda Feb 16 at 21:47
  • 1
    I know. But I frankly don't use this feature because I want to have my variable names be consistent and thus use $ as a prefix all the time. – framp Feb 18 at 19:31
1

You are absolutely right!

The quoting within double square brackets makes no sense at all, at least in this case.

But since I use double quotes daily -- especially for single square bracket expressions, passing arguments to functions and scripts, as well as variable assignment sometimes (which is completely useless for simple delcarations) -- I guess some people, at least I do, write double quotes around variable expansions instinctively.

Double quoting can give you a sense of savety. It is like coming home where double quotes are. - D. Kummer

A benefit of doing double quotes consequently and comprehensibly -- but only as it makes sense -- is that coworkers who are new to bash can learn how to write more stable scripts. It also accentuates the fact that the art of data processing with bash is more about separating data streams (including variables) by field separators and pipe them through filters. As soon as you got your data chunks separated from the stream, hold them together with double quotes!

Another benefit could be the better readability of bash scripts with double quoted strings within a code highlighting editor.

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.