在Bash中,测试数组是否包含某个值的最简单方法是什么?


当前回答

如何检查一个Bash数组是否包含一个值


假阳性匹配

array=(a1 b1 c1 d1 ee)

[[ ${array[*]} =~ 'a' ]] && echo 'yes' || echo 'no'
# output:
yes

[[ ${array[*]} =~ 'a1' ]] && echo 'yes' || echo 'no'
# output:
yes

[[ ${array[*]} =~ 'e' ]] && echo 'yes' || echo 'no'
# output:
yes

[[ ${array[*]} =~ 'ee' ]] && echo 'yes' || echo 'no'
# output:
yes

精确匹配

为了寻找精确匹配,你的正则表达式模式需要在值的前后添加额外的空格,如(^|[[:space:]])" value "($|[[:space:]])

# Exact match

array=(aa1 bc1 ac1 ed1 aee)

if [[ ${array[*]} =~ (^|[[:space:]])"a"($|[[:space:]]) ]]; then
    echo "Yes";
else
    echo "No";
fi
# output:
No

if [[ ${array[*]} =~ (^|[[:space:]])"ac1"($|[[:space:]]) ]]; then
    echo "Yes";
else
    echo "No";
fi
# output:
Yes

find="ac1"
if [[ ${array[*]} =~ (^|[[:space:]])"$find"($|[[:space:]]) ]]; then
    echo "Yes";
else
    echo "No";
fi
# output:
Yes

有关更多用法示例,示例的来源在这里

其他回答

虽然这里有几个很好的和有用的答案,但我没有找到一个似乎是性能、跨平台和健壮性的正确组合;所以我想分享一下我为我的代码编写的解决方案:

#!/bin/bash

# array_contains "$needle" "${haystack[@]}"
#
# Returns 0 if an item ($1) is contained in an array ($@).
#
# Developer note:
#    The use of a delimiter here leaves something to be desired. The ideal
#    method seems to be to use `grep` with --line-regexp and --null-data, but
#    Mac/BSD grep doesn't support --line-regexp.
function array_contains()
{
    # Extract and remove the needle from $@.
    local needle="$1"
    shift

    # Separates strings in the array for matching. Must be extremely-unlikely
    # to appear in the input array or the needle.
    local delimiter='#!-\8/-!#'

    # Create a string with containing every (delimited) element in the array,
    # and search it for the needle with grep in fixed-string mode.
    if printf "${delimiter}%s${delimiter}" "$@" | \
        grep --fixed-strings --quiet "${delimiter}${needle}${delimiter}"; then
        return 0
    fi

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

字符串:

for i in "${array[@]}"
do
    if [ "$i" == "$yourValue" ] ; then
        echo "Found"
    fi
done

如果您想做一个快速而复杂的测试,看看是否值得遍历整个数组以获得精确匹配,Bash可以像对待标量一样对待数组。测试标量中的匹配项,如果没有,则跳过循环节省时间。显然你会得到假阳性。

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

这将输出“Checking”和“Match”。使用array=(word "two words" something),它只会输出"Checking"。使用array=(单词“two widgets”什么的)将没有输出。

我通常只使用:

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

非零值表示找到了匹配。

... 实际上,为了解决它不能与needle1和needle2工作的问题,如果你只想要一个精确匹配,没有更多,没有更少,只需在-o后面添加一个w标志,用于整个单词匹配:

inarray=$(echo ${haystack[@]} | grep -ow "needle" | wc -w)
$ myarray=(one two three)
$ case "${myarray[@]}" in  *"two"*) echo "found" ;; esac
found