19

Anyone know why this happens? Is this a bug of bash?

x='mnt:[4026532411]'

[[ $x == $x ]] && echo OK

I am expecting result OK, but it did not.

Of course, this works

[[ "$x" == "$x" ]] && echo OK

But as I know, bash [[ ]] have a merit that no need to quote var when compare.

x='a b'
[[ $x == $x ]] && echo OK

works.

Ironical things is

x='mnt:[4026532411]'

[[ $x != $x ]] && echo Oh my god

result is Oh my god

osexp2000
  • 2,910
  • 30
  • 29
  • 4
    Just to follow up the answers with a look at the question title: `[[ [a] == [a] ]]` will not be "true" because the left-hand operand is the literal 3-character string "[a]" and the right-hand operand is a pattern that can only match the letter "a" – glenn jackman Jun 23 '18 at 16:30
  • 4
    Conversely, `[ [a] = [a] ]` **is** true, because `[` is different from `[[`: the `=` operator in `[` is only a string equality operator. – glenn jackman Jun 23 '18 at 16:32
  • 2
    `x='mnt:4'; y='mnt:[0123456]'; [[ $x == $y ]] && echo OK` – Cyrus Jun 23 '18 at 16:40
  • 4
    "...no need to quote var when compare" - I don't think that was good advice. I would suggest quoting anyway whenever you want to do a pure string comparison, for precisely this reason. – David Z Jun 23 '18 at 19:00

2 Answers2

19

The unquoted right-hand side of == and != is treated as a pattern, not a literal string. mnt:[4026532411] will match mnt: followed by exactly one of 0, 1, 2, 3, 4, 5, or 6, since the patterns mnt:[4026532411] and mnt:[0123456] are equivalent. To match the lieral string, you need to quote the expansion.

x='mnt:[4026532411]'

[[ $x == "$x" ]] && echo OK
chepner
  • 497,756
  • 71
  • 530
  • 681
  • So basically it's a complete lie that `[[` `]]` avoids the need for quoting? – user541686 Jun 23 '18 at 21:05
  • 2
    @Mehrdad Not entirely. Quoting in `[` is meant for countering word-splitting. That's what people refer to when they mention `[[` doesn't need quotes. And in chepner's answer the unquoted `$x` on left hand side is perfectly fine - it doesn't need quotes there. But again, there's different issue - `[[` treats right hand side of `==` as pattern. So....context matters, I guess – Sergiy Kolodyazhnyy Jun 23 '18 at 22:00
  • @SergiyKolodyazhnyy: I mean I guess I'm saying the context *doesn't* matter; either you need to quote, or you don't. – user541686 Jun 23 '18 at 22:36
  • The *normal* reasons for quoting (to avoid word-splitting and path expansion) don't apply, but the fact that `==` and `!=` inside `[[...]]` can perform pattern matching introduces a *new* reason to quote. – chepner Jun 23 '18 at 23:33
  • Of course you don't need to quote if the right hand side is a pattern. – user202729 Jun 24 '18 at 03:22
  • @chepner Yes, I agree, this was a bad decision of mine. For some reason I thought, it would be easier to redefine a pair of variables at the top of my script. But I don't think so anymore =) – zinovyev Jul 19 '19 at 12:34
6

What you are seeing is do do this sentence from the bash man page:

When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching, as if the extglob shell option were enabled.

As you may already know, [...] in the shell allows matching from a group of characters. That is, given the files:

$ ls
fileA fileB fileC fileD

Running ls file[AB] will yield:

fileA fileB

So in your expression, mnt:[1234] is interpreted in a similar fashion.

larsks
  • 277,717
  • 41
  • 399
  • 399