How to check if a string contains a substring in Bash

ID : 177

viewed : 233

Tags : stringbashshellsubstringstring

Top 5 Answer for How to check if a string contains a substring in Bash

vote vote

93

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 =~.

vote vote

82

If you prefer the regex approach:

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

80

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 
vote vote

67

stringContain variants (compatible or case independent)

As these Stack Overflow answers tell mostly about Bash, I've posted a case independent Bash function at the very bottom of this post...

Anyway, there is my

Compatible answer

As there are already a lot of answers using Bash-specific features, there is a way working under poorer-featured shells, like BusyBox:

[ -z "${string##*$reqsubstr*}" ] 

In practice, this could give:

string='echo "My string"' for reqsubstr in 'o "M' 'alt' 'str';do   if [ -z "${string##*$reqsubstr*}" ] ;then       echo "String '$string' contain substring: '$reqsubstr'."     else       echo "String '$string' don't contain substring: '$reqsubstr'."     fi   done 

This was tested under Bash, Dash, KornShell (ksh) and ash (BusyBox), and the result is always:

String 'echo "My string"' contain substring: 'o "M'. String 'echo "My string"' don't contain substring: 'alt'. String 'echo "My string"' contain substring: 'str'. 

Into one function

As asked by @EeroAaltonen here is a version of the same demo, tested under the same shells:

myfunc() {     reqsubstr="$1"     shift     string="$@"     if [ -z "${string##*$reqsubstr*}" ] ;then         echo "String '$string' contain substring: '$reqsubstr'.";       else         echo "String '$string' don't contain substring: '$reqsubstr'."     fi } 

Then:

$ myfunc 'o "M' 'echo "My String"' String 'echo "My String"' contain substring 'o "M'.  $ myfunc 'alt' 'echo "My String"' String 'echo "My String"' don't contain substring 'alt'. 

Notice: you have to escape or double enclose quotes and/or double quotes:

$ myfunc 'o "M' echo "My String" String 'echo My String' don't contain substring: 'o "M'.  $ myfunc 'o "M' echo \"My String\" String 'echo "My String"' contain substring: 'o "M'. 

Simple function

This was tested under BusyBox, Dash, and, of course Bash:

stringContain() { [ -z "${2##*$1*}" ]; } 

Then now:

$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi no $ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi yes 

... Or if the submitted string could be empty, as pointed out by @Sjlver, the function would become:

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; } 

or as suggested by Adrian G√ľnter's comment, avoiding -o switches:

stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ];};} 

Final (simple) function:

And inverting the tests to make them potentially quicker:

stringContain() { [ -z "$1" ] || { [ -z "${2##*$1*}" ] && [ -n "$2" ];};} 

With empty strings:

$ if stringContain '' ''; then echo yes; else echo no; fi yes $ if stringContain 'o "M' ''; then echo yes; else echo no; fi no 

Case independent (Bash only!)

For testing strings without care of case, simply convert each string to lower case:

stringContain() {     local _lc=${2,,}     [ -z "$1" ] || { [ -z "${_lc##*${1,,}*}" ] && [ -n "$2" ] ;} ;} 

Check:

stringContain 'o "M3' 'echo "my string"' && echo yes || echo no no stringContain 'o "My' 'echo "my string"' && echo yes || echo no yes if stringContain '' ''; then echo yes; else echo no; fi yes if stringContain 'o "M' ''; then echo yes; else echo no; fi no 
vote vote

52

You should remember that shell scripting is less of a language and more of a collection of commands. Instinctively you think that this "language" requires you to follow an if with a [ or a [[. Both of those are just commands that return an exit status indicating success or failure (just like every other command). For that reason I'd use grep, and not the [ command.

Just do:

if grep -q foo <<<"$string"; then     echo "It's there" fi 

Now that you are thinking of if as testing the exit status of the command that follows it (complete with semi-colon), why not reconsider the source of the string you are testing?

## Instead of this filetype="$(file -b "$1")" if grep -q "tar archive" <<<"$filetype"; then #...  ## Simply do this if file -b "$1" | grep -q "tar archive"; then #... 

The -q option makes grep not output anything, as we only want the return code. <<< makes the shell expand the next word and use it as the input to the command, a one-line version of the << here document (I'm not sure whether this is standard or a Bashism).

Top 3 video Explaining How to check if a string contains a substring in Bash

Related QUESTION?