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


当前回答

a=(b c d)

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

如果你喜欢,你可以使用相同的长选项:

--fixed-strings --quiet --line-regexp --null-data

其他回答

@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

使用参数展开:

如果参数为空或未设置,则什么都没有 替换,否则词的展开就会被替换。

declare -A myarray
myarray[hello]="world"

for i in hello goodbye 123
do
  if [ ${myarray[$i]:+_} ]
  then
    echo ${!myarray[$i]} ${myarray[$i]} 
  else
    printf "there is no %s\n" $i
  fi
done

下面的代码检查给定值是否在数组中,并返回其从零开始的偏移量:

A=("one" "two" "three four")
VALUE="two"

if [[ "$(declare -p A)" =~ '['([0-9]+)']="'$VALUE'"' ]];then
  echo "Found $VALUE at offset ${BASH_REMATCH[1]}"
else
  echo "Couldn't find $VALUE"
fi

匹配是在完整的值上完成的,因此设置VALUE="three"将不匹配。

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

一行的解决方案

printf '%s\0' "${myarray[@]}" | grep -F -x -z -- 'myvalue'

解释

printf语句打印数组中的每个元素,以空字符分隔。

grep语句使用以下标志来匹配一个包含myvalue字符串的项(不多不少):

-z/——null-data -行以0字节而不是换行符结束。 -f /——fixed-strings -将pattern解释为固定字符串,而不是正则表达式。 -x/——line-regexp -只选择与整行完全匹配的匹配项。 ——-标记命令行选项的结束,使Grep处理“myvalue”作为一个非选项参数,即使它以破折号开始

为什么我们使用空字节\0而不是换行符\n?数组的元素实际上可能包含换行符。(如果您知道它没有,请随意删除-z grep选项,并将%s\n替换为您的第一个printf参数。)


使用

把这个放进一个if…然后声明:

if printf '%s\0' "${myarray[@]}" | grep -Fxqz -- 'myvalue'; then
    # ...
fi

我在grep表达式中添加了-q标志,这样它就不会打印匹配项;它只会将匹配的存在视为“真”。

更新:感谢presto8指出——line-regexp标志。谢谢Tino,你指出了数组项中可以存在换行符的情况。