Check if a Bash array contains a value

2019-01-01 01:34发布

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.

标签: arrays bash
30条回答
无色无味的生活
2楼-- · 2019-01-01 01:54

A small addition to @ghostdog74's answer about using case logic to check that array contains particular value:

myarray=(one two three)
word=two
case "${myarray[@]}" in  ("$word "*|*" $word "*|*" $word") echo "found" ;; esac

Or with extglob option turned on, you can do it like this:

myarray=(one two three)
word=two
shopt -s extglob
case "${myarray[@]}" in ?(*" ")"$word"?(" "*)) echo "found" ;; esac

Also we can do it with if statement:

myarray=(one two three)
word=two
if [[ $(printf "_[%s]_" "${myarray[@]}") =~ .*_\[$word\]_.* ]]; then echo "found"; fi
查看更多
姐姐魅力值爆表
3楼-- · 2019-01-01 01:56

Expanding on the above answer from Sean DiSanti, I think the following is a simple and elegant solution that avoids having to loop over the array and won't give false positives due to partial matches

function is_in_array {
    local ELEMENT="${1}"
    local DELIM=","
    printf "${DELIM}%s${DELIM}" "${@:2}" | grep -q "${DELIM}${ELEMENT}${DELIM}"
}

Which can be called like so:

$ haystack=("needle1" "needle2" "aneedle" "spaced needle")
$ is_in_array "needle" "${haystack[@]}"
$ echo $?
1
$ is_in_array "needle1" "${haystack[@]}"
$ echo $?
0
查看更多
时光乱了年华
4楼-- · 2019-01-01 01:56

Here is a small contribution :

array=(word "two words" words)  
search_string="two"  
match=$(echo "${array[@]:0}" | grep -o $search_string)  
[[ ! -z $match ]] && echo "found !"  

Note: this way doesn't distinguish the case "two words" but this is not required in the question.

查看更多
美炸的是我
5楼-- · 2019-01-01 01:57

My version of the regular expressions technique that's been suggested already:

values=(foo bar)
requestedValue=bar

requestedValue=${requestedValue##[[:space:]]}
requestedValue=${requestedValue%%[[:space:]]}
[[ "${values[@]/#/X-}" =~ "X-${requestedValue}" ]] || echo "Unsupported value"

What's happening here is that you're expanding the entire array of supported values into words and prepending a specific string, "X-" in this case, to each of them, and doing the same to the requested value. If this one is indeed contained in the array, then the resulting string will at most match one of the resulting tokens, or none at all in the contrary. In the latter case the || operator triggers and you know you're dealing with an unsupported value. Prior to all of that the requested value is stripped of all leading and trailing whitespace through standard shell string manipulation.

It's clean and elegant, I believe, though I'm not too sure of how performant it may be if your array of supported values is particularly large.

查看更多
其实,你不懂
6楼-- · 2019-01-01 01:57
a=(b c d)

if printf '%s\0' "${a[@]}" | grep -Fqxz c
then
  echo 'array “a” contains value “c”'
fi

If you prefer you can use equivalent long options:

--fixed-strings --quiet --line-regexp --null-data
查看更多
孤独寂梦人
7楼-- · 2019-01-01 01:58

I typically just use:

inarray=$(echo ${haystack[@]} | grep -o "needle" | wc -w)

non zero value indicates a match was found.

查看更多
登录 后发表回答