1

Suppose I have a string,

a="This is a string"

and an array,

b=("This is my" "sstring")

I want to execute an if condition if any substring of a lies in b which is true because "This is" is a substring of the first element of b.

In case of two strings I know how to check if $x is a substring of $y using,

if [[ $y == *$x* ]]; then
 #Something
fi

but since $x is an array of strings I don't know how to do it without having to explicitly loop through the array.

9
  • 2
    You have to explicitly loop through the array. Commented Dec 26, 2021 at 12:32
  • 3
    So you want the result to match both strings in b, because the substring i is in them? Is the double s in sstring a typo? Commented Dec 26, 2021 at 12:38
  • @Jens Since "This is" of a is a substring of "This is my" of the first element of b, I want a match to occur. The double s is not a typo. I don't want a match by string being a substring of sstring. I am looking for matches only upto words separated by a space. Commented Dec 26, 2021 at 12:46
  • 1
    It will be good to clarify which substring boundaries you're assuming in a and b -- according to your comment, you're only looking for space-separated substrings of a. Does this also apply for matches in b? For example should an entry like "banapple gas" in b match, since a is a space-separated substring in a? Commented Dec 26, 2021 at 13:11
  • 1
    Do you then mean you want to know whether any substring of a is a substring of any element of b? Because I would ordinarily be inclined to interpret "lies in [array] b" as "is equal to an element of b", yet that is not consistent with your example. Note also that your [[ $a == *${b[0]}* ]] would evaluate to false with your example data. Commented Dec 26, 2021 at 13:29

3 Answers 3

2

This might be all you need:

$ printf '%s\n' "${b[@]}" | grep -wFf <(tr ' ' $'\n' <<<"$a")
This is my

Otherwise - a shell is a tool to manipulate files/processes and sequence calls to tools. The guys who invented shell also invented awk for shell to call to manipulate text. What you're trying to do is manipulate text so there's a good chance you should be using awk instead of shell for whatever it is you're doing that this task is a part of.

$ printf '%s\n' "${b[@]}" | 
awk -v a="$a" '
    BEGIN { split(a,words) }
    { for (i in words) if (index($0,words[i])) { print; f=1; exit} }
    END { exit !f }
'
This is my

The above assumes a doesn't contain any backslashes, if it can then use this instead:

printf '%s\n' "${b[@]}" | a="$a" awk 'BEGIN{split(ENVIRON["a"],words)} ...'

If any element in b can contain newlines then:

printf '%s\0' "${b[@]}" | a="$a" awk -v RS='\0' 'BEGIN{split(ENVIRON["a"],words)} ...'
Sign up to request clarification or add additional context in comments.

Comments

0

Here is how to match the maximum number of words from string a to entries of array b:

#!/usr/bin/env bash

a="this is a string"
b=("this is my" "string" )

# tokenize a words into an array
read -ra a_words <<<"$a"

match()
{
  # iterate entries of array b
  for e in "${b[@]}"; do

    # tokenize entry words into an array
    read -ra e_words <<<"$e"

    # initialize counter/length to the shortest MIN words count
    i=$(( ${#a_words[@]} < ${#e_words[@]} ? ${#a_words[@]} : ${#e_words[@]} ))

    # iterate matching decreasing number of words
    while [ 0 -lt "$i" ]; do

      # return true it matches
      [ "${e_words[*]::$i}" = "${a_words[*]::$i}" ] && return

      # decrease number of words to match
      i=$(( i - 1 ))
    done
  done

  # reaching here means no match found, return false
  return 1
}

if match; then
  printf %s\\n 'It matches!'
fi

Comments

0

You can split the $a into an array, then loop both arrays to find matches:

a="this is a string"
b=( "this is my" "string")

# Make an array by splitting $a on spaces
IFS=' ' read -ra aarr <<< "$a"

for i in "${aarr[@]}"
do 
  for j in "${b[@]}"
  do
    if [[ $j == *"$i"* ]]; then
      echo "Match: $i : $j"
      break
    fi
  done
done

# Match: this : this is my
# Match: is : this is my
# Match: string : string

If you need to handle substrings in $a (e.g. this is, is my etc) then you will need to loop over the array, generating all possible substrings:

for (( length=1; length <= "${#aarr[@]}"; ++length )); do
  for (( start=0; start + length <= "${#aarr[@]}"; ++start )); do
    substr="${aarr[@]:start:length}"
    for j in "${b[@]}"; do
      if [[ $j == *"${substr}"* ]]; then
        echo "Match: $substr : $j"
        break
      fi
    done
  done
done

# Match: this : this is my
# Match: is : this is my
# Match: string : string
# Match: this is : this is my

1 Comment

Misread the question - have updated just now to be correct for individual words, but will look at handling 'phrases' too...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.