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


当前回答

保持简单:

Array1=( "item1" "item2" "item3" "item-4" )
var="item3"

count=$(echo ${Array1[@]} | tr ' ' '\n' | awk '$1 == "'"$var"'"{print $0}' | wc -l)
[ $count -eq 0 ] && echo "Not found" || echo "found"

其他回答

以下是我的看法。

如果可以避免的话,我宁愿不使用bash for循环,因为运行它需要时间。如果有什么东西必须循环,让它是用比shell脚本更低级的语言编写的东西。

function array_contains { # arrayname value
  local -A _arr=()
  local IFS=
  eval _arr=( $(eval printf '[%q]="1"\ ' "\${$1[@]}") )
  return $(( 1 - 0${_arr[$2]} ))
}

这是通过创建一个临时关联数组_arr来实现的,它的索引是从输入数组的值派生出来的。(请注意,关联数组在bash 4及以上版本中可用,因此此函数在bash的早期版本中无效。)我们设置$IFS以避免在空格上分词。

该函数不包含显式循环,不过bash内部会遍历输入数组以填充printf。printf格式使用%q来确保输入数据被转义,这样它们就可以安全地用作数组键。

$ a=("one two" three four)
$ array_contains a three && echo BOOYA
BOOYA
$ array_contains a two && echo FAIL
$

注意,这个函数使用的所有东西都是bash内置的,因此没有外部管道拖您的后腿,即使在命令展开中也是如此。

如果你不喜欢使用eval…你可以自由地使用另一种方法。: -)

下面是实现这一点的一个小函数。搜索字符串是第一个参数,其余是数组元素:

set +e #otherwise the script will exit on error
containsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 0; done
  return 1
}

该函数的测试运行如下:

$ array=("something to search for" "a string" "test2000")
$ containsElement "a string" "${array[@]}"
$ echo $?
0
$ containsElement "blaha" "${array[@]}"
$ echo $?
1

这是一个小小的贡献:

array=(word "two words" words)  
search_string="two"  
match=$(echo "${array[@]:0}" | grep -o $search_string)  
[[ ! -z $match ]] && echo "found !"  

注意:这种方法不区分大小写“两个单词”,但在问题中不需要这样做。

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

保持简单:

Array1=( "item1" "item2" "item3" "item-4" )
var="item3"

count=$(echo ${Array1[@]} | tr ' ' '\n' | awk '$1 == "'"$var"'"{print $0}' | wc -l)
[ $count -eq 0 ] && echo "Not found" || echo "found"