1

Bash allows checking for a substring.

It is even possible to use the wildcard symbol * inside the search string:

# works
line="foo bar baz"
if [[ $line == *"foo "*" baz"* ]]; then
  echo "found"
fi

1.) But how do I pass the search string including the wildcard through a variable?

# fails
line="foo bar baz"
search='foo "*" baz'
echo "$search"
if [[ $line == *"$search"* ]]; then
  echo "found"
fi

2.) And if it is possible through escaping: How do I manipulate $search, so the user of my script can simply pass foo * baz?

The only solution I found is this, but it is limited to a specific maximum amount of wildcards and it does not feel like the best way to solve this:

line="foo bar baz"
search="foo * baz"
IFS=\* read -r search1 search2 search3 search4 <<< "$search"
if [[ $line == *"$search1"*"$search2"*"$search3"*"$search4"* ]]; then
  echo "found"
fi
mgutt
  • 5,867
  • 2
  • 50
  • 77

2 Answers2

2

This is actually simple: don't quote the variable containing the search pattern, or include quotes in the search variable (unless you want to search for literal quotes).

line="foo bar baz"
search="foo * baz"
if [[ $line == *$search* ]]; then
  echo "found"
fi

Explanation: if parts of the pattern (i.e. the thing on the right side of the = or == operator in [[ ]]) are quoted, they're treated as literal rather than as glob patterns. Thus, putting double-quotes around $search makes bash treat the * in its value as just a literal character rather than a wildcard. Removing the double-quotes makes bash treat it as a wildcard.

Note that this doesn't apply to quotes in the variable's value; those will be treated as literal whether or not the variable is quoted. So if you use search='foo "*" baz', it's going to be looking for double-quotes in the line whether or not you double-quote $search.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • Ah nice. Finally I needed to escape the other wildcard characters like `search=${search//[/\\[}; search=${search//]/\\]}; search=${search//\?/\\?}` as they should be searchable as a literal string. Any other characters, which I need to escape? – mgutt Mar 11 '23 at 09:32
  • If there are any literal backslashes, you need to escape them as well (and do it before the other characters, or you'll be escaping *those* escapes...). If you have `extglob` (extended glob syntax) enabled, things are more complex and I'm not sure exactly what needs escaping. – Gordon Davisson Mar 11 '23 at 10:13
1

In this case, you can use case:

$ search="foo * baz"; case "foo bar baz" in $search) echo found ;; esac
found
KamilCuk
  • 120,984
  • 8
  • 59
  • 111