26

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.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Meerkat
  • 263
  • 3
  • 5
  • 6
    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 '19 at 12:27
  • 15
    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 '19 at 13:15
  • 2
    @sudodus I don't think that's true for [[ ]], only for [ ]. – Benjamin W. Feb 15 '19 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 '19 at 20:32
  • "Let's say we have 2 integers in a bash script:" - You don't have two integers, you have two strings containing a decimal integer representation. The only datatype shells know is strings; there are no integer variables in shell like there are in, say, C or Python. – marcelm Feb 15 '19 at 21:14
  • If you knew for certain they would always have those values, the quotes wouldn't be necessary, but if you knew for certain they would always have those values there would be no point in comparing them for equality since three will never be equal to five. – David Conrad Feb 15 '19 at 21:21
  • 3
    @marcelm, Bash, ksh and Zsh have integer variables, and within [[ ]] they also coerce the operands of -eq to integers. – ilkkachu Feb 15 '19 at 23:01
  • 1
    If you're happy with one or several of the answers, upvote them. If one is solving your issue, accepting it would be the best way of saying "Thank You!" Accepting an answer also indicates to future readers that the answer actually solved the problem. – Kusalananda Feb 18 '19 at 20:31
  • 1
    Ok, thanks. But how can I upvote and accept an answer ? – Meerkat Feb 18 '19 at 20:54

5 Answers5

38

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:

ilkkachu
  • 138,973
terdon
  • 242,166
  • 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 '19 at 10:52
  • 6
    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 '19 at 13:05
  • The right hard should still be quoted if the variable has any glob characters, e.g. a='*'; [[ 'a' = $a ]] && echo oops – user000001 Feb 15 '19 at 14:36
  • 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 '19 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 '19 at 16:11
  • 2
    @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 '19 at 16:32
  • Related: Conditional Constructs "Word splitting and filename expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed." – jesse_b Feb 15 '19 at 16:32
  • 1
    For the record, the only universally portable safe places to not quote variables (and other expansions) are the first field of the case statement (but not the patterns to match in the case statement), and in regular variable assignments (but not in variable assignments as part of export). – mtraceur Feb 15 '19 at 20:09
16

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.)
jamesdlin
  • 838
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.

glenn jackman
  • 85,964
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.

framp
  • 171
  • 1
  • 8
  • 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 '19 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 '19 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.

domson
  • 341