80

Read that for comparing strings inside if we need to use double square brackets. Some books says that comparison can be done by =. But it works with the == too.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Is there a difference between = and == in the comparison?

0

3 Answers 3

77

In bash (like in ksh where bash copied that syntax from), [[ $a == $b ]] is not comparison, it's pattern matching. You need [[ $a == "$b" ]] for byte-to-byte equality comparison. = is the same as == in any shell that supports [[...]].

[[...]] is not standard sh syntax. The [ command is standard, and the standard comparison operator there is = (though some [ implementations also recognise ==¹).

Just like in any argument to any command, variable expansions must be quoted to prevent split+glob and empty removal (only the latter being performed in zsh), so:

[ "$a" = "$b" ]

In standard sh, pattern matching is done with case:

case $a in
  ($b) ...
esac

For completeness, other equality-like operators you may come across in shell scripts:

  • [ "$a" -eq "$b" ]: standard [ operator to compare decimal integer numbers. Some [ implementations allow blanks around the numbers, some allow arbitrary arithmetic expressions, but that's not portable. Portably, one can use [ "$(($a))" -eq "$(($b))" ] for that. See also [ "$((a == b))" -ne 0 ] which would be the standard equivalent (except that POSIXly, the behaviour is only specified if $a and $b contain integer constants) of:

  • ((a == b)), from ksh and also found in zsh and bash, returns true if the evaluation of the arithmetic expression stored in $a yields the same number as that of $b. Typically, that's used for comparing numbers. Note that there are variations between shells as to how arithmetic expressions are evaluated and what numbers are supported (for instance bash and some implementation/versions of ksh don't support floating point or treat numbers with leading zeros as octal).

  • expr "$a" = "$b" does a number comparison if both operands are recognised as decimal integer numbers (some allowing blanks around the number), and otherwise checks if the two string operands have the same sorting order. It would also fail for values of $a or $b that are expr operators like (, substr...

  • awk -- 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": if $a and $b are recognised as numbers (at least decimal integer and floating point numbers like 1.2, -1.5e-4, leading trailing blanks ignored, some also recognising hexadecimal, octal or anything recognised by strtod()), then a numeric comparison is performed. Otherwise, depending on the implementation, it's either a byte-to-byte string comparison, or like for expr a strcoll() comparison, that is whether $a and $b sort the same.

See also:


¹ that includes GNU [ and the [ builtin of ksh, bash, yash, some though not all ash-based shells and zsh, however note that in zsh, =cmd is a special filename expansion operator (expanded in the same contexts as ~user is) that expands to the path of the corresponding command, so there, unless you turn off the equals option to disable that feature, you'd need to write it [ "$a" '==' "$b" ] or you'd get an error that the = command is not found. Same for [ "$string" '=~' "$regexp" ]

3
  • 1
    though some [ implementations also recognise == ahhh thanks for that! Bash was succeeding but zsh failing on [ $x == $y ]. Both shells accepted double-bracket+double-equals OR single-bracket+single-equals, but only bash allowed the mixed POSIX first scenario
    – xref
    May 20, 2021 at 23:22
  • @xref, zsh's [ builtin does support the == operator, but there, the =cmd operator interferes with it. See edit. May 21, 2021 at 5:11
  • @StéphaneChazelas = and == don't behave exactly the same way. If you use double quotes then you don't have to quote variables. See my post...
    – zomega
    Dec 3, 2021 at 10:12
29

These are equivalent in bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

The first two $x variables don't have to be quoted. Bash performs word splitting and pathname expansion inside [ but not inside [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]] is a string comparison but [[ $x = $y ]] is a pattern matching expression:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq is only meant to be used with integers:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

See also BashFAQ/031: What is the difference between test, [ and [[ ?.

7

Both = and == are operators. In some languages (like C) one is used to assign a value to a variable and the other to compare values (result of arithmetic expressions). In fact, both operators are exactly that inside Arithmetic Evaluation. A $((a=23)) is an assignment, a $((a==23)) is an Arithmetic Comparison.

$ echo "$((a=11)) $((a==23))" "$((a=23))" "$((a==23))"
11 0 23 1

But inside test constructs (all of test and […] and [[…]]) both operators are intended to mean the same and perform the same operation.

So, all of this options:

test "$a" =  "$b"
   [ "$a" =  "$b" ]
  [[ "$a" =  "$b" ]]
test "$a" == "$b"
   [ "$a" == "$b" ]
  [[ "$a" == "$b" ]]

Are equivalent inside bash to test binary equality (variables quoted). If the right variable is unquoted it may be interpreted as a pattern and matched accordingly: as a pattern not as a literal string.

The quoted operators \= and \== are also equivalent when used in test and […]. But the quoted operator \== fails inside [[…]].

For other shells the results are varied (correct result should be Y - (true false), an exit code different from 0 (true) and 1 (false) is reported as failure wih ¤). Some shells fail with - - (the exit code is always 1).

                     | dash  ksh   bash  zsh   
  test a  =  "$b"    | Y -   Y -   Y -   Y -    
     [ a  =  "$b" ]  | Y -   Y -   Y -   Y -    
    [[ a  =  "$b" ]] | ¤ ¤   Y -   Y -   Y -    
  test a  == "$b"    | ¤ ¤   Y -   Y -   - -    
     [ a  == "$b" ]  | ¤ ¤   Y -   Y -   - -    
    [[ a  == "$b" ]] | ¤ ¤   Y -   Y -   Y -    
  test a \=  "$b"    | Y -   Y -   Y -   Y -    
     [ a \=  "$b" ]  | Y -   Y -   Y -   Y -    
    [[ a \=  "$b" ]] | ¤ ¤   Y -   - -   - -    
  test a \== "$b"    | ¤ ¤   Y -   Y -   Y -    
     [ a \== "$b" ]  | ¤ ¤   Y -   Y -   Y -    
    [[ a \== "$b" ]] | ¤ ¤   Y -   - -   - -

All options work in ksh, quoted operators fail in bash and zsh (inside [[…]]) and the unquoted \= and \== also fail in zsh (outside of [[…]]).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .