Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are Bash conditions not symmetrical when using wildcards?

Tags:

bash

Suppose I have the following Bash snippet:

if [[ "$foo" == *"$bar"* ]] ; then
  echo 'condition is true'
fi

In English, you might describe the above code with: if bar is a substring of foo then...

However, how come when we switch the sides of the condition, we don't get the same results?

if [[ *"$bar"* == "$foo" ]] ; then
  echo 'condition is true'
fi

Perhaps I have a misunderstanding of when the wildcard is evaluated?

like image 267
wcarhart Avatar asked May 30 '20 00:05

wcarhart


2 Answers

It's an explicit design decision. Here's man bash:

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

Pathname expansion is not performed in [[ .. ]], so regular rules around that don't apply.

Treating both as a pattern would be pretty strange. Should [[ a* == [a]* ]] be true because the right pattern matches the left string, false because the left pattern does not match the right string, or true because both patterns match the same set of strings?

like image 184
that other guy Avatar answered Nov 12 '22 15:11

that other guy


The == comparison operator behaves differently within a double-brackets :

[[ $foo == 0* ]]   # True if $foo starts with foo "0" (wildcard matching).
[[ $foo == "0" ]] # True if $foo is equal to 0* (literal matching).

This works because bash's builtin [[ operator treats the right-hand-side of an == test as a pattern:

When the == and != operators are used, the string to the right of the operator is used as >a pattern and pattern matching is performed.

the test builtin tests wheather strings are equal the [[expression]] syntax adds comparison test for string operators, the > and < operators compare strings for oder (i.e :"aa" < "bb"). the operator tests for pattern match not just equality [[ string = pattern ]] is true if string matches pattern, this operator is not symmertical , the pattern must appear on the right side of the equal sign, i.e [[ foo = a* ]] is true (=0),whereas [[ a* = foo ]] is false(=1)

[[ "foo" == f* ]] && echo $? # 0

[[ f* == "foo" ]] && echo $? || echo $? # 1

How come [[ $foo == $bar ]] is true and [[ $bar == $foo ]] is false?

The == operator is not symmetrical. It takes a string on the left and a pattern on the right. However, if you double quote the right hand side, which removes the special meaning of pattern match characters, then this becomes a string comparison so that [[ "$foo" == "bar" ]] and [[ "$bar" == "$foo" ]] are equivalent.

like image 39
Mahmoud Odeh Avatar answered Nov 12 '22 17:11

Mahmoud Odeh