I wanna test whether a string has "substring". Most answers online is based on Bash. I tried
if [ $string == "*substring*" ]
which was not working. Currently
if echo ${string} | grep -q "substring"
worked. Is there any other better way.
Using POSIX compliant parameter-expansion and with the classic test-command.
#!/bin/sh
substring=ab
string=abc
if [ "$string" != "${string%"$substring"*}" ]; then
echo "$substring present in $string"
fi
(or) explicitly using the test operator as
if test "$string" != "${string%$substring*}" ; then
$substring for this to work for string=a*b and substring=*, for example. [ "$string" != "${string%"$substring"*}" ] (This might be sufficient, though.)'*' need quoting in $substring.In a POSIX-features only shell you won't be able to do general pattern or regex matching inside a conditional without the help of an external utility.
That said:
Kenster's helpful answer shows how to use the branches of a case ... esac statement for pattern matching.
Inian's helpful answer shows how to match indirectly inside a conditional, using patterns as part of parameter expansions.
Your own grep approach is certainly an option, though you should double-quote ${string}:
if echo "${string}" | grep -q "substring"; ...
A slightly more efficient way is to use the expr utility, but note that per POSIX it is limited to BREs (basic regular expressions), which are limited:
string='This text contains the word "substring".'
if expr "$string" : ".*substring" >/dev/null; then echo "matched"; fi
Note that the regex - the 3rd operand - is implicitly anchored at the start of the input, hence the need for .*.
>/dev/null suppresses expr's default output, which is the length of the matched string in this case. (If nothing matches, the output is 0, and the exit code is set to 1).
If you're just testing for substrings (or anything that can be matched using filename wildcards) you can use case:
#!/bin/sh
while read line; do
case "$line" in
*foo*) echo "$line" contains foo ;;
*bar*) echo "$line" contains bar ;;
*) echo "$line" isnt special ;;
esac
done
$ ./testit.sh
food
food contains foo
ironbar
ironbar contains bar
bazic
bazic isnt special
foobar
foobar contains foo
This is basic Bourne shell functionality. It doesn't require any external programs, it's not bash-specific, and it predates POSIX. So it should be pretty portable.
Short answer is no, not if you are trying to use vanilla sh, without Bash extensions. On many modern systems, /bin/sh is actually a link to /bin/bash, which provides a superset of sh's functionality (for the most part). Your original attempt would have worked with Bash's builtin [[ extended test command: http://mywiki.wooledge.org/BashFAQ/031
[[, so probably won't work for you.grep -qthough, except that is starts a separate subprocess.