M BUZZ CRAZE NEWS
// news

How to determine if a string is a substring of another in bash?

By John Parsons

I want to see if a string is inside a portion of another string.
e.g.:

'ab' in 'abc' -> true
'ab' in 'bcd' -> false

How can I do this in a conditional of a bash script?

0

7 Answers

[[ "bcd" =~ "ab" ]]
[[ "abc" =~ "ab" ]]

the brackets are for the test, and as it is double brackets, it can so some extra tests like =~.

So you could use this form something like

var1="ab"
var2="bcd"
if [[ "$var2" =~ "$var1" ]]; then echo "pass"
else echo "fail"
fi

Edit: corrected "=~", had flipped.

2

You can use the form ${VAR/subs} where VAR contains the bigger string andsubs is the substring your are trying to find:

my_string=abc
substring=ab
if [ "${my_string/$substring}" = "$my_string" ] ; then echo "${substring} is not in ${my_string}"
else echo "${substring} was found in ${my_string}"
fi

This works because ${VAR/subs} is equal to $VAR but with the first occurrence of the string subs removed, in particular if $VAR does not contains the word subs it won't be modified.

6

Using bash filename patterns (aka "glob" patterns)

substr=ab
[[ abc == *"$substr"* ]] && echo yes || echo no # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no # no
1

The following two approaches will work on any POSIX-compatible environment, not just in bash:

substr=ab
for s in abc bcd; do if case ${s} in *"${substr}"*) true;; *) false;; esac; then printf %s\\n "'${s}' contains '${substr}'" else printf %s\\n "'${s}' does not contain '${substr}'" fi
done
substr=ab
for s in abc bcd; do if printf %s\\n "${s}" | grep -qF "${substr}"; then printf %s\\n "'${s}' contains '${substr}'" else printf %s\\n "'${s}' does not contain '${substr}'" fi
done

Both of the above output:

'abc' contains 'ab'
'bcd' does not contain 'ab'

The former has the advantage of not spawning a separate grep process.

Note that I use printf %s\\n "${foo}" instead of echo "${foo}" because echo might mangle ${foo} if it contains backslashes.

1

shell case statement

This is the most portable solution, will work even on old Bourne shells and Korn shell

#!/bin/bash
case "abcd" in *$1*) echo "It's a substring" ;; *) echo "Not a substring" ;;
esac

Sample run:

$ ./case_substr.sh "ab"
It's a substring
$ ./case_substr.sh "whatever"
Not a substring

Note that you don't have to specifically use echo you can use exit 1 and exit 0 to signify success or failure.

What we could do as well, is create a function (which can be used in large scripts if necessary) with specific return values ( 0 on match, 1 on no match):

$ ./substring_function.sh
ab is substring
$ cat substring_function.sh
#!/bin/sh
is_substring(){ case "$2" in *$1*) return 0;; *) return 1;; esac
}
main(){ if is_substring "ab" "abcdefg" then echo "ab is substring" fi
}
main $@

grep

$ grep -q 'ab' <<< "abcd" && echo "it's a substring" || echo "not a substring"
it's a substring

This particular approach is useful with if-else statements in bash. Also mostly portable

AWK

$ awk '$0~/ab/{print "it is a substring"}' <<< "abcd"
it is a substring

Python

$ python -c 'import sys;sys.stdout.write("it is a substring") if "ab" in sys.stdin.read() else exit(1)' <<< "abcd"
it is a substring

Ruby

$ ruby -e ' puts "is substring" if ARGV[1].include? ARGV[0]' "ab" "abcdef"
is substring
6

Mind the [[ and ":

[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
[ $a == z* ] # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).

So as @glenn_jackman said, but mind that if you wrap the whole second term in double quotes, it will switch the test to literal matching.

Source:

Similar to edwin's answer, but with improved portability for posix & ksh, and a touch less noisy than Richard's:

substring=ab
string=abc
if [ "$string" != "${string%$substring*}" ]; then echo "$substring IS in $string"
else echo "$substring is NOT in $string"
fi
string=bcd
if [ "$string" != "${string%$substring*}" ]; then echo "$string contains $substring"
else echo "$string does NOT contain $substring"
fi

Output:

abc contains ab
bcd does NOT contain ab

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy