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

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

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


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

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

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.

| improve this answer | |
  • I think that you should change the sequence of the echo statements. Because I get ab is not in abc – Lucio May 25 '13 at 0:05
  • You are right! :P – edwin May 25 '13 at 0:06
  • Mmm.. No, the script is wrong. Like that I get ab was found in abc, but if I use substring=z I get z was found in abc – Lucio May 25 '13 at 0:08
  • 1
    Now I get ab is not in abc. But z was found in abc. This is funny :D – Lucio May 25 '13 at 0:11
  • 1
    Duh! The echoes were right at the start of this! XD – edwin May 25 '13 at 0:13

[[ "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

if [[ "$var2" =~ "$var1" ]]; then
    echo "pass"
    echo "fail"

Edit: corrected "=~", had flipped.

| improve this answer | |
  • 1
    I get fail with this parameters: var2="abcd" – Lucio May 25 '13 at 0:02
  • 3
    @Lucio The correct is [[ $string =~ $substring ]]. I updated the answer. – Eric Carvalho May 25 '13 at 0:38

Using bash filename patterns (aka "glob" patterns)

[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no
| improve this answer | |
  • if [[ "$JAVA_OPTS" != "-XX:+UseCompressedOops" ]]; then export JAVA_OPTS="$JAVA_OPTS -XX:+UseCompressedOops"; fi – Mike Slinn Feb 10 '16 at 17:41

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

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

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.

| improve this answer | |
  • First version works perfectly for finding substring of monitor name in list of xrandr monitor names stored in variable. +1 and welcome to 1K rep club :) – WinEunuuchs2Unix Feb 10 '18 at 16:31

shell case statement

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

case "abcd" in
    *$1*) echo "It's a substring" ;;
    *) echo "Not a substring" ;;

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                                

    case "$2" in
        *$1*) return 0;;
        *) return 1;;

   if is_substring "ab" "abcdefg"
       echo "ab is substring"

main $@


$ 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 '$0~/ab/{print "it is a substring"}' <<< "abcd"                                                             
it is a substring


$ 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 -e ' puts "is substring" if  ARGV[1].include? ARGV[0]'  "ab" "abcdef"                                             
is substring
| improve this answer | |
  • +1 for going above and beyond everyone else. I noticed here and on other stack exchange sites no answer returns the substring's offset within the string. Which is tonight's mission :) – WinEunuuchs2Unix Nov 17 '18 at 23:36
  • @WinEunuuchs2Unix Going to do that in bash ? – Sergiy Kolodyazhnyy Nov 17 '18 at 23:38
  • Yes and No. I'm doing a Frankenstein project where python get's all the gmail.com messages metadata and bash parses it and presents a GUI list with drill down. I found the answer though here: stackoverflow.com/questions/5031764/… – WinEunuuchs2Unix Nov 17 '18 at 23:42
  • @WinEunuuchs2Unix OK. Sounds interesting. I'd personally prefer to parse everything in Python. It has far more capabilities for text processing than bash alone. – Sergiy Kolodyazhnyy Nov 17 '18 at 23:46
  • I know your preferences for about two years and I respect them. But I'm just learning Python and getting yad to work within it seems cumbersome to me. Not to mention all the array processing which I'm already comfortable with in bash. But at least I wrote my first python script to suck everything out of google's gmail.com into Linux flat file right? :) – WinEunuuchs2Unix Nov 17 '18 at 23:49

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: http://tldp.org/LDP/abs/html/comparison-ops.html

| improve this answer | |

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


if [ "$string" != "${string%$substring*}" ]; then
    echo "$substring IS in $string"
    echo "$substring is NOT in $string"

if [ "$string" != "${string%$substring*}" ]; then
    echo "$string contains $substring"
    echo "$string does NOT contain $substring"


abc contains ab
bcd does NOT contain ab
| improve this answer | |

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.