Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

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?

share|improve this question

5 Answers 5

up vote 7 down vote accepted

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.

share|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
Sorry again I forgot the $ in substring. –  edwin May 25 '13 at 0:10
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

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

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.

share|improve this answer
I get fail with this parameters: var2="abcd" –  Lucio May 25 '13 at 0:02
@Lucio The correct is [[ $string =~ $substring ]]. I updated the answer. –  Eric Carvalho May 25 '13 at 0:38
@EricCarvalho opps, thanks for correcting it. –  demure May 25 '13 at 0:49

Using bash filename patterns (aka "glob" patterns)

[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no
share|improve this answer

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.

share|improve this answer

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

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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