nathan
nathan

Reputation: 854

How to check substring in Bourne Shell?

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.

Upvotes: 7

Views: 5133

Answers (4)

mklement0
mklement0

Reputation: 439317

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

Upvotes: 6

Kenster
Kenster

Reputation: 25439

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.

Upvotes: 3

Inian
Inian

Reputation: 85790

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

Upvotes: 10

Mad Physicist
Mad Physicist

Reputation: 114440

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

Upvotes: 0

Related Questions