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


当前回答

我提出了这个方法,它只能在zsh中工作,但我认为一般方法是不错的。

arr=( "hello world" "find me" "what?" )
if [[ "${arr[@]/#%find me/}" != "${arr[@]}" ]]; then
    echo "found!"
else
    echo "not found!"
fi

只有当${arr[@]/#pattern/}开始或${arr[@]/%pattern/}结束时,才能从每个元素中取出模式。这两个替换可以在bash中工作,但同时${arr[@]/#%pattern/}只能在zsh中工作。

如果修改后的数组等于原始数组,则不包含该元素。

编辑:

这个在bash中工作:

 function contains () {
        local arr=(${@:2})
        local el=$1
        local marr=(${arr[@]/#$el/})
        [[ "${#arr[@]}" != "${#marr[@]}" ]]
    }

在替换之后,它比较两个数组的长度。如果数组包含该元素,则替换将完全删除该元素,并且计数将不同。

其他回答

containsElement () { for e in "${@:2}"; do [[ "$e" = "$1" ]] && return 0; done; return 1; }

现在正确处理空数组。

我通常只使用:

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

非零值表示找到了匹配。

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

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

我通常编写这类实用程序来操作变量的名称,而不是变量的值,这主要是因为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.

@ghostdog74关于使用大小写逻辑检查数组包含特定值的回答的一个小补充:

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

或者打开extglob选项,你可以这样做:

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

我们也可以用if语句:

myarray=(one two three)
word=two
if [[ $(printf "_[%s]_" "${myarray[@]}") =~ .*_\[$word\]_.* ]]; then echo "found"; fi

扩展上面来自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