Test if a string contains a substring

Use the =~ operator to make regular expression comparisons:

#!/bin/bash
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file =~ $testseq ]];
then
    echo "True"
else
    echo "False"
fi

This way, it will compare if $file has $testseq on its contents.

user@host:~$ ./string.sh
False

If I change testseq="Const":

user@host:~$ ./string.sh
True

But, be careful with what you feed $testseq with. If the string on it somehow represents a regex (like [0-9] for example), there is a higher chance to trigger a "match".

Reference:

  • Advanced Bash Script guide

You need to interpolate the $testseq variable with one of the following ways:

  • $file == *_"$testseq"_* (here $testseq considered as a fixed string)

  • $file == *_${testseq}_* (here $testseq considered as a pattern).

Or the _ immediately after the variable's name will be taken as part of the variable's name (it's a valid character in a variable name).


file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

Using case ... esac is one of the simplest ways to perform a pattern match in a portable way. It works as a "switch" statement in other languages (bash, zsh, and ksh93 also allows you to do fall-through in various incompatible ways). The patterns used are the standard file name globbing patterns.

The issue you are having is due to the fact that _ is a valid character in a variable name. The shell will thus see *_$testseq_* as "*_ followed by the value of the variable $testseq_ and an *". The variable $testseq_ is undefined, so it will be expanded to an empty string, and you end up with *_*, which obviously matches the $file value that you have. You may expect to get True as long as the filename in $file contains at least one underscore.

To properly delimit the name of the variable, use "..." around the expansion: *_"$testseq"_*. This would use the value of the variable as a string. Would you want to use the value of the variable as a pattern, use *_${testseq}_* instead.

Another quick fix is to include the underscores in the value of $testseq:

testseq="_gen_"

and then just use *"$testseq"* as the pattern (for a string comparison).