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
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
.