How to determine if a string is a substring of another in bash?
I want to see if a string is inside a portion of another string.
e.g.:
'ab' in 'abc' -> true
'ab' in 'bcd' -> falseHow can I do this in a conditional of a bash script?
07 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"
fiEdit: corrected "=~", had flipped.
2You 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}"
fiThis 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.
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
donesubstr=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
doneBoth 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.
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" ;;
esacSample run:
$ ./case_substr.sh "ab"
It's a substring
$ ./case_substr.sh "whatever"
Not a substringNote 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 substringThis 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 substringPython
$ python -c 'import sys;sys.stdout.write("it is a substring") if "ab" in sys.stdin.read() else exit(1)' <<< "abcd"
it is a substringRuby
$ 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"
fiOutput:
abc contains ab
bcd does NOT contain ab