Categories
bash sh shell string substring

How to check if a string contains a substring in Bash

3223

I have a string in Bash:

string="My string"

How can I test if it contains another string?

if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Where ?? is my unknown operator. Do I use echo and grep?

if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

That looks a bit clumsy.

4

  • 4

    Hi, if empty strings are false, why do you consider it clumsy? It was the only way that worked for me, despite the proposed solutions.

    May 5, 2015 at 6:14


  • 1

    You can use the expr command here

    – cifer

    Mar 2, 2016 at 3:08

  • 6

    Here’s one for posix shells: stackoverflow.com/questions/2829613/…

    – sehe

    Apr 8, 2016 at 15:31

  • 1

    Please use $needle in a $haystack idiom in your example. It’s much easier to read and understand.

    Nov 30, 2021 at 20:19

4494

You can use Marcus’s answer (* wildcards) outside a case statement, too, if you use double brackets:

string='My long string'
if [[ $string == *"My long"* ]]; then
  echo "It's there!"
fi

Note that spaces in the needle string need to be placed between double quotes, and the * wildcards should be outside. Also note that a simple comparison operator is used (i.e. ==), not the regex operator =~.

3

  • 179

    Also note that you can reverse the comparison by just switching to != in the test. Thanks for the answer!

    Jul 30, 2009 at 17:14

  • 2

    Hmm, with this exact code, I get [[: not found. Any idea what’s wrong? I’m using GNU bash, version 4.1.5(1), on Ubuntu.

    – Jonik

    Nov 16, 2010 at 11:20

  • 74

    @Jonik: You may be missing the shebang or have it as #!/bin/sh. Try #!/bin/bash instead.

    Dec 17, 2010 at 5:18

886

If you prefer the regex approach:

string='My string';

if [[ $string =~ "My" ]]; then
   echo "It's there!"
fi

4

  • 3

    Had to replace an egrep regex in a bash script, this worked perfectly!

    Feb 14, 2012 at 5:10

  • 120

    The =~ operator already searches the whole string for a match; the .*‘s here are extraneous. Also, quotes are generally preferable to backslashes: [[ $string =~ "My s" ]]

    – bukzor

    Jun 5, 2013 at 18:15


  • 23

    @bukzor Quotes stopped working here as of Bash 3.2+: tiswww.case.edu/php/chet/bash/FAQ E14). It’s probably best to assign to a variable (using quotes), then compare. Like this: re="My s"; if [[ $string =~ $re ]]

    – seanf

    May 12, 2015 at 0:55


  • 55

    Test if it does NOT contain a string: if [[ ! "abc" =~ "d" ]] is true.

    Jan 24, 2016 at 14:57

458

I am not sure about using an if statement, but you can get a similar effect with a case statement:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

4

  • 99

    This is probably the best solution since it is portable to posix shells. (a.k.a. no bashisms)

    Jan 4, 2014 at 17:02

  • 36

    @technosaurus I find it rather odd to criticize “bashism” in a question that has only bash tag 🙂

    – P.P

    Dec 17, 2015 at 23:27


  • 60

    @P.P. It’s not so much a criticism as the preference of a more universal solution over a more limited one. Please consider that, years later, people (like me) will stop by to look for this answer and may be pleased to find one that’s useful in a wider scope than the original question. As they say in the Open Source world: “choice is good!”

    Jun 3, 2016 at 7:56


  • 2

    @technosaurus, FWIW [[ $string == *foo* ]] also works in some POSIX compliant sh versions (e.g. /usr/xpg4/bin/sh on Solaris 10) and ksh (>= 88)

    May 1, 2017 at 10:00