tags:

views:

47

answers:

4

In Bash, what is the simplest way to test if an array contains a certain value?

EDIT: with help from the answers and the comments, after some testing, I came up with this:

function contains() {
    local n=$#
    local value=${!n}
    for ((i=1;i < $#;i++)) {
        if [ "${!i}" == "${value}" ]; then
            echo "y"
            return 0
        fi
    }
    echo "n"
    return 1
}

A=("one" "two" "three four")
if [ $(contains "${A[@]}" "one") == "y" ]; then
    echo "contains one"
fi
if [ $(contains "${A[@]}" "three") == "y" ]; then
    echo "contains three"
fi

I'm not sure if it's the best solution, but it seems to work.

+1  A: 

There is sample code at this link that shows how to replace a substring from an array. You can make a copy of the array and try to remove the target value from the copy. If the copy and original are then different, then the target value exists in the original string.

The straightforward (but potentially more time-consuming) solution is to simply iterate through the entire array and check each item individually. This is what I typically do because it is easy to implement and you can wrap it in a function (see this link for info on passing an array to a function).

bta
+1  A: 
for i in "${array[@]}"
do
    if [ "$i" -eq "$yourValue" ] ; then
        echo "Found"
    fi
done

For strings:

for i in "${array[@]}"
do
    if [ "$i" == "$yourValue" ] ; then
        echo "Found"
    fi
done
Scott
What if an element of the array contains a space? Moreover, would it be possible to make this a function?
Paolo Tedesco
Any solution that does not rely on questionable bash hojiggery is preferable.
Matt Kane
That said, you can use an indexed for loop and avoid getting killed when an array element contains IFS: for (( i = 0 ; i < ${#array[@]} ; i++ ))
Matt Kane
@Paolo: Quoting the array variable in the `for` statement makes that work.
Dennis Williamson
@Matt: You have to be careful using `${#}` since Bash supports sparse arrays.
Dennis Williamson
@Paolo, if your array contains a space then just compare it as a string. a space is a string as well.
Scott
@Paolo: You can make that a function, but arrays can't be passed as arguments so you'll have to treat it as a global.
Dennis Williamson
Dennis is right. From the bash reference manual: "If the word is double-quoted, ... ${name[@]} expands each element of name to a separate word"
Matt Kane
I was pretty much sticking with the question, which said 'simplest'. This might not be the most efficient or best
Scott
+1  A: 

If you want to do a quick and dirty test to see if it's worth iterating over the whole array to get a precise match, Bash can treat arrays like scalars. Test for a match in the scalar, if none then skipping the loop saves time. Obviously you can get false positives.

array=(word "two words" words)
if [[ ${array[@]} =~ words ]]
then
    echo "Checking"
    for element in "${array[@]}"
    do
        if [[ $element == "words" ]]
        then
            echo "Match"
        fi
    done
fi

This will output "Checking" and "Match". With array=(word "two words" something) it will only output "Checking". With array=(word "two widgets" something) there will be no output.

Dennis Williamson
A: 
$ myarray=(one two three)
$ case "${myarray[@]}" in  *"two"*) echo "found" ;; esac
found