Tom Bennett
Tom Bennett

Reputation: 179

Bash: test if a variable exists within another variable?

I have two variables, both are a list of filenames that have been moved by a script.

Variable 1: Generated by a 'read' loop of a larger variable. At any given moment it only contains one filename.

var1 = pic1.jpg

var1 = pic2 duplicate.jpg

var1 = pic3(dup).jpg

var1 = pic4.jpg

var1 = subfolder/subfolder picture.png

As shown above, the filenames can contain spaces, but do not always.

Variable 2: A string containing a list of files, each filename being separated by a \n newline character.

var2 = pic1.jpg \n pic2 duplicate.jpg \n pic3(dup).jpg \n pic4.jpg

I am attempting to test if the contents of var1 can be found in var2:

    listcontains() {
        for list_item in $1; do
            # Does $list_item exist in $2?
            if [[ "$list_item" =~ "$2" ]]; then
                return 0
            else
                return "1"
            fi
        done

    }

    # Call function to see if var1 is in var2
    if listcontains "$var1" "$var2"
       then
           # var1 is in var2; do stuff...
       else
           # Do different stuff...
   fi

This logic is clearly wrong, or the syntax is wrong, as it always returns a non-match at the moment:

does pic2 exist in pic2 duplicate.jpg
pic2.jpg
pic3(dup).jpg
pic3.jpg?
no

does pic3(dup).jpg exist in pic2 duplicate.jpg
pic2.jpg
pic3(dup).jpg
pic3.jpg?
no

I'm still learning bash, so if anybody could help me then it would be massively appreciated.

Upvotes: 1

Views: 1056

Answers (2)

Frederick Zhang
Frederick Zhang

Reputation: 3683

Here I show you how it works in the console, you can then copy the code to a bash script file.

Frederick@Frederick-PC ~
$ for ele in "${var1[@]}"; do echo $ele; done
abc
def

Frederick@Frederick-PC ~
$ echo "$var2"
abc
ghi

Frederick@Frederick-PC ~
$ IFS=$'\n' read -rd '' -a array <<< "$var2"

Frederick@Frederick-PC ~
$ for ele in "${array[@]}"; do echo $ele; done
abc
ghi

Frederick@Frederick-PC ~
$ for ele in "${var1[@]}"; \
> do
> if [[ ${array[*]} =~ $ele ]]
> then
> echo "var2 contains $ele"
> else
> echo "var2 does not contain $ele"
> fi
> done
var2 contains abc
var2 does not contain def

Upvotes: 0

Etan Reisner
Etan Reisner

Reputation: 80931

The right-hand side of =~ is the regex pattern. The left-hand side is the string to match it against.

You have your arguments backwards. You also aren't accounting for any regex special characters in $list_item which would throw off your matches.

Are your $list_item entries partial filenames or complete filenames? If they are complete filenames then it might be easier to use a read loop and do exact matches against each line in $var2 instead of this (even better would beto use an associative array of filenames in $var2 to make the matching much faster).

That being said using a string for filenames is a bad idea because it makes doing anything with them (especially if they can have spaces/etc.) difficult to impossible.

Upvotes: 1

Related Questions