2

From bash manual, for conditional expressions

string1 == string2
string1 = string2

True if the strings are equal.

  1. When used with the [[ command, this performs pattern matching as described above (see Section 3.2.4.2 [Conditional Constructs], page 10).

    • What does "pattern matching" mean here?

    • What is "pattern matching" opposed to here?

    • If not used with [[ but with other commands, what does "this" perform?

  2. ‘=’ should be used with the test command for posix conformance.

    • What does POSIX say here?

    • What is the sentence opposed to?

    • Can == be used with test command? I tried and it seems yes.

    • Can = be used with other commands besides test? I tried = with [[ and [, and it seems yes.

  3. what are the differences between == and =?

    In Bash 4.3, I tried == and = with test, [[, and [. == and = look the same to me.

    Can == and = be used interchangeably in any conditional expression?

Thanks.

8

POSIX test (or [ ... ]) only knows about the one with a single equal sign:

s1 = s2
True if the strings s1 and s2 are identical; otherwise, false.

But Bash accepts the double equal sign too, though the builtin help doesn't admit to that (the manual does):

$ help test | grep =  -A1
  STRING1 = STRING2
                 True if the strings are equal.
  STRING1 != STRING2
                 True if the strings are not equal.

As for other shells, it depends:

$ dash -c '[ x == x ] && echo foo'
dash: 1: [: x: unexpected operator
$ zsh -c '[ x == x ] && echo foo'
zsh:1: = not found
$ ksh93 -c '[ x == x ] && echo foo'
foo

zsh is a bit odd here, == is considered a special operator, so it must be quoted:

$ zsh -c '[ x "==" x ] && echo foo'
foo

The external test/[ utility from GNU coreutils on my Debian supports == (but the manual doesn't admit that), the one on OS X doesn't.

So, with test/[ .. ], use = as it's more widely supported.


With the [[ ... ]] construct, both = and == are equal (at least in Bash) and the right side of the operator is taken as a pattern, like in a filename glob, unless it is quoted. (Filenames are not expanded within [[ ... ]])

$ bash -c '[[ xxx == x* ]] && echo foo'
foo

But of course that construct isn't standard:

$ dash -c '[[ xxx == x* ]] && echo foo'
dash: 1: [[: not found
  • Thanks. Do you mean that [[ ... ]] doesn't exist in POSIX shell, and == doesn't exist in POSIX shell either? – Tim Jul 26 '17 at 21:27
  • @Tim, yes, that's correct. Although "exist" is a slippery word. "Aren't specified by POSIX" is more correct. POSIX is a set of specifications, not an actual shell. – Wildcard Jul 27 '17 at 0:31
  • Try help [[ and search for ==. – Arrow Jul 27 '17 at 1:38
  • zsh's [ supports ==. It's just that =something is a special operator (when not emulating other shell), so needs quoted. Same problem with =~: [ x '=~' . ], [ x '==' x ]. – Stéphane Chazelas Jul 27 '17 at 6:23
  • @StéphaneChazelas, I did wonder about that, and the confusing error message, thanks for the clarification! – ilkkachu Jul 27 '17 at 10:20
2

In bash, there are four conditions about equality:

  • The simple and most basic (and only posix compatible) = inside [ … ] (or test):
    Only performs equality (byte by byte) of two strings.

     STRING1 = STRING2
                 True if the strings are equal.
    
  • The extended == . Which still performs (only) an equality test.

    $ [ aaaa == aaaa ] && echo yes
    yes
    
    $ [ aaaa == a* ] && echo yes
    $
    

    Be careful that the unquoted a* will be expanded to a filename (or several) if a matching filename exist in the pwd. In specific: an existing file named aaaa will make the code output yes. If there are no files matching, the exact comparison is afected by the failglob and nullglob shell options.

  • A = inside a [[ is exactly equivalent to:

  • A == inside a [[ does both byte-by-byte and glob matching.

    If the string or variable on the right side of the == is quoted, a byte comparison is made. If all the bytes are equal, the result of the [[ is "good" (0).

    If the string, or preferable in all cases: a variable, is unquoted, the match is performed as in a filename glob.

    $ [[ aaaa == "aaaa" ]] && echo yes
    yes
    
    $ a='aaaa'
    $ [[ aaaa == "$a" ]] && echo yes
    yes
    
    $ a='a*'
    $ [[ aaaa == "$a" ]] && echo yes
    $
    
    $ a='a*'
    $ [[ aaaa == $a ]] && echo yes
    yes
    

It is interesting to note that the unquoted aaaa also work:

$ a='aaaa'
$ [[ aaaa = $a ]] && echo yes
yes

This happens because the string inside the variable does not have any expandable glob characters *, +, ?, [ and the extended (if activated) |, @ and ! . But that is usually a risky bet to use.

  • [ aaaa == a* ] && echo yes would output yes if there was a file called aaaa in the current directory (and no other file whose name starts with a). See also the effect of the failglob and nullglob option for when the glob doesn't match. – Stéphane Chazelas Jul 27 '17 at 6:26
  • But of course ! ... thanks. @StéphaneChazelas – Arrow Jul 27 '17 at 6:35

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.