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


当前回答

扩展上面来自Sean DiSanti的答案,我认为下面是一个简单而优雅的解决方案,它避免了对数组进行循环,并且不会由于部分匹配而给出假阳性

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

可以这样称呼:

$ haystack=("needle1" "needle2" "aneedle" "spaced needle")
$ is_in_array "needle" "${haystack[@]}"
$ echo $?
1
$ is_in_array "needle1" "${haystack[@]}"
$ echo $?
0

其他回答

我通常编写这类实用程序来操作变量的名称,而不是变量的值,这主要是因为bash不能通过引用传递变量。

下面是一个使用数组名称的版本:

function array_contains # array value
{
    [[ -n "$1" && -n "$2" ]] || {
        echo "usage: array_contains <array> <value>"
        echo "Returns 0 if array contains value, 1 otherwise"
        return 2
    }

    eval 'local values=("${'$1'[@]}")'

    local element
    for element in "${values[@]}"; do
        [[ "$element" == "$2" ]] && return 0
    done
    return 1
}

这样,问题示例就变成:

array_contains A "one" && echo "contains one"

etc.

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

我通常只使用:

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

非零值表示找到了匹配。

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

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

如果您想做一个快速而复杂的测试,看看是否值得遍历整个数组以获得精确匹配,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”什么的)将没有输出。

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