81

我想知道是否有一种有效的方法来检查 Bash 中的数组中是否存在元素?我正在寻找类似于我可以在 Python 中执行的操作,例如:

arr = ['a','b','c','d']

if 'd' in arr:
    do your thing
else:
    do something

我已经看到在 Bash 4+ 中使用 bash 的关联数组的解决方案,但我想知道是否还有其他解决方案。

请理解,我知道简单的解决方案是在数组中迭代,但我不希望这样。

4

8 回答 8

112

你可以这样做:

if [[ " ${arr[*]} " == *" d "* ]]; then
    echo "arr contains d"
fi

例如,如果您查找“a b”,这将给出误报——该子字符串在连接的字符串中,但不是作为数组元素。无论您选择什么分隔符,都会出现这种困境。

最安全的方法是遍历数组,直到找到元素:

array_contains () {
    local seeking=$1; shift
    local in=1
    for element; do
        if [[ $element == "$seeking" ]]; then
            in=0
            break
        fi
    done
    return $in
}

arr=(a b c "d e" f g)
array_contains "a b" "${arr[@]}" && echo yes || echo no    # no
array_contains "d e" "${arr[@]}" && echo yes || echo no    # yes

这是一个“更干净”的版本,您只需传递数组名称,而不是其所有元素

array_contains2 () { 
    local array="$1[@]"
    local seeking=$2
    local in=1
    for element in "${!array}"; do
        if [[ $element == "$seeking" ]]; then
            in=0
            break
        fi
    done
    return $in
}

array_contains2 arr "a b"  && echo yes || echo no    # no
array_contains2 arr "d e"  && echo yes || echo no    # yes

对于关联数组,有一种非常简洁的方法可以测试数组是否包含给定的-v运算符

$ declare -A arr=( [foo]=bar [baz]=qux )
$ [[ -v arr[foo] ]] && echo yes || echo no
yes
$ [[ -v arr[bar] ]] && echo yes || echo no
no

请参阅手册中的6.4 Bash 条件表达式

于 2013-01-16T20:37:30.827 回答
36

除了明显的警告之外,如果您的阵列实际上与上面的阵列一样,您可以这样做

if [[ ${arr[*]} =~ d ]]
then
  do your thing
else
  do something
fi
于 2013-01-16T19:58:54.567 回答
24

1)初始化数组arr并添加元素

2) 设置要搜索的变量SEARCH_STRING

3)检查您的数组是否包含元素

arr=()
arr+=('a')
arr+=('b')
arr+=('c')

SEARCH_STRING='b'

if [[ " ${arr[*]} " == *"$SEARCH_STRING"* ]];
then
    echo "YES, your arr contains $SEARCH_STRING"
else
    echo "NO, your arr does not contain $SEARCH_STRING"
fi
于 2016-12-30T12:04:29.373 回答
19

如果数组元素不包含空格,另一种(可能更易读)解决方案是:

if echo ${arr[@]} | grep -q -w "d"; then 
    echo "is in array"
else 
    echo "is not in array"
fi
于 2015-12-03T12:45:52.427 回答
3
array=("word" "two words") # let's look for "two words"

使用grepprintf

(printf '%s\n' "${array[@]}" | grep -x -q "two words") && <run_your_if_found_command_here>

使用for

(for e in "${array[@]}"; do [[ "$e" == "two words" ]] && exit 0; done; exit 1) && <run_your_if_found_command_here>

对于 not_found 结果添加|| <run_your_if_notfound_command_here>

于 2016-11-01T14:25:45.930 回答
3

由于 bash 没有内置的 in 数组运算符,并且=~运算符或[[ "${array[@]" == *"${item}"* ]]符号让我感到困惑,我通常grep与 here-string 结合使用:

colors=('black' 'blue' 'light green')
if grep -q 'black' <<< "${colors[@]}"
then
    echo 'match'
fi

但是请注意,当要搜索的项目完全包含但不等于另一个项目时,这会遇到与许多其他答案相同的误报问题:

if grep -q 'green' <<< "${colors[@]}"
then
    echo 'should not match, but does'
fi

如果这对您的用例来说是个问题,您可能无法绕过数组循环:

for color in "${colors[@]}"
do
    if [ "${color}" = 'green' ]
    then
        echo "should not match and won't"
        break
    fi
done

for color in "${colors[@]}"
do
    if [ "${color}" = 'light green' ]
    then
        echo 'match'
        break
    fi
done
于 2019-07-04T05:50:43.843 回答
2

就计算时间而言,这是另一种可能比迭代更快的方法。没有把握。这个想法是将数组转换为字符串,截断它,并获取新数组的大小。

例如,要查找“d”的索引:

arr=(a b c d)    
temp=`echo ${arr[@]}`
temp=( ${temp%%d*} )
index=${#temp[@]}

你可以把它变成一个函数,比如:

get-index() {

    Item=$1
    Array="$2[@]"

    ArgArray=( ${!Array} )
    NewArray=( ${!Array%%${Item}*} )

    Index=${#NewArray[@]}

    [[ ${#ArgArray[@]} == ${#NewArray[@]} ]] && echo -1 || echo $Index

}

然后你可以打电话:

get-index d arr

它会回显 3,它可以分配为:

index=`get-index d arr`
于 2015-02-26T02:52:47.220 回答
0

FWIW,这是我使用的:

expr "${arr[*]}" : ".*\<$item\>"

这适用于任何数组项或搜索目标中没有分隔符的情况。我不需要为我的应用程序解决一般情况。

于 2015-07-13T19:13:11.987 回答