51

I'm using BASH, and I don't know how to find a substring. It keeps failing, I've got a string (should this be an array?)

Below, LIST is a string list of database names, SOURCE is the reply, one of those databases. The following still doesn't work:

echo "******************************************************************"
echo "*                  DB2 Offline Backup Script                     *"
echo "******************************************************************"
echo "What's the name of of the  database you would like to backup?"
echo "It will be named one in this list:"
echo ""
LIST=`db2 list database directory | grep "Database alias" | awk '{print $4}'`
echo $LIST
echo ""
echo "******************************************************************"
echo -n ">>> "
read -e SOURCE

if expr match "$LIST" "$SOURCE"; then
    echo "match"
    exit -1
else
    echo "no match"
fi
exit -1

I've also tried this but doesn't work:

if [ `expr match "$LIST" '$SOURCE'` ]; then
jww
  • 97,681
  • 90
  • 411
  • 885
edumike
  • 3,149
  • 7
  • 27
  • 33

8 Answers8

88
LIST="some string with a substring you want to match"
SOURCE="substring"
if echo "$LIST" | grep -q "$SOURCE"; then
  echo "matched";
else
  echo "no match";
fi
dietbuddha
  • 8,556
  • 1
  • 30
  • 34
  • 1
    2 issues to consider with this approach: (1) grep uses regex so some chars will match unexpected or cause errors; (2) Using grep (or anything that's not built in to bash) spawns a separate process which will run slower (only matters in larger scale cases). – codesniffer Mar 11 '18 at 04:19
38

You can also compare with wildcards:

if [[ "$LIST" == *"$SOURCE"* ]]

Christopher Bottoms
  • 11,218
  • 8
  • 50
  • 99
sreimer
  • 4,913
  • 2
  • 33
  • 43
8

This works in Bash without forking external commands:

function has_substring() {
   [[ "$1" != "${2/$1/}" ]]
}

Example usage:

name="hello/world"
if has_substring "$name" "/"
then
   echo "Indeed, $name contains a slash!"
fi
Hisham H M
  • 6,398
  • 1
  • 29
  • 30
  • 1
    The advantage to this solution is that it doesn't rely on any external commands nor file descriptors (via redirection or pipes). – bill.lee Nov 15 '17 at 01:05
  • 4
    Note that this is using a regex to search for the substring (and also does an out-of-place replace), so special chars in the search (substring) can cause unexpected results. But if regex is fine, then why not just do a regex search (ie. no need for the replace)? Syntax example: if [[ "$string" =~ $substring ]] – codesniffer Mar 11 '18 at 04:38
7

If you're using bash you can just say

if grep -q "$SOURCE" <<< "$LIST" ; then
    ...
fi
sorpigal
  • 25,504
  • 8
  • 57
  • 75
1

You can use "index" if you only want to find a single character, e.g.:

LIST="server1 server2 server3 server4 server5"
SOURCE="3"
if expr index "$LIST" "$SOURCE"; then
    echo "match"
    exit -1
else
    echo "no match"
fi

Output is:

23
match
Angelo Babudro
  • 591
  • 1
  • 5
  • 7
1
expr match "$LIST" '$SOURCE'

don't work because of this function search $SOURCE from begin of the string and return the position just after pattern $SOURCE if found else 0. So you must write another code:

expr match "$LIST" '.*'"$SOURCE" or expr "$LIST" : '.*'"$SOURCE"

The expression $SOURCE must be double quoted so as a parser may set substitution. Single quoted not substitute and the code above will search textual string $SOURCE from the beginning of the $LIST. If you need the beginning of the string subtract the length $SOURCE e.g ${#SOURCE}. You may write also

expr "$LIST" : ".*\($SOURCE\)"

This function just extract $SOURCE from $LIST and return it. You'll get empty string else. But they problem with double double quote. I don't know how it resolve without using additional variable. It's light solution. So you may write in C. There is ready function strstr. Don't use expr index, So is very attractive. But index search not substring and only first char.

Anatoly
  • 11
  • 2
0

expr is used instead of [ rather than inside it, and variables are only expanded inside double quotes, so try this:

if expr match "$LIST" "$SOURCE"; then

But I'm not really clear what SOURCE is supposed to represent.

It looks like your code will read in a pattern from standard input, and exit if it matches a database alias, otherwise it will echo "ok". Is that what you want?

Mikel
  • 24,855
  • 8
  • 65
  • 66
0

Well, what about something like this:

PS3="Select database or <Q> to quit: "
select DB in db1 db2 db3; do
   [ "${REPLY^*}" = 'Q' ] && break
   echo "Should backup $DB..."
done
Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134