如何检查 zsh 数组是否包含给定值?

bde*_*ham 20 zsh

假设我有一个非关联数组,其定义如下

my_array=(foo bar baz)
Run Code Online (Sandbox Code Playgroud)

如何检查数组是否包含给定的字符串?我更喜欢可以在if块的条件内使用的解决方案(例如if contains $my_array "something"; then ...)。

bde*_*ham 24

如果您有一个数组$my_array并且想知道它是否包含字符串foo,一个可能的测试是

[[ ${my_array[(ie)foo]} -le ${#my_array} ]]
Run Code Online (Sandbox Code Playgroud)

数组元素的完整准确值必须是foo;它不是子字符串检查或类似的东西。

如果要查看变量的值是否$my_string在数组中,请使用

[[ ${my_array[(ie)$my_string]} -le ${#my_array} ]]
Run Code Online (Sandbox Code Playgroud)

这种(ie)语法不是很明显。它是在解释标旗部分zsh的手册。这i部分意味着我们正在使用“反向下标”:${my_array[1]}我们传递一个值并要求第一个给出该值的下标,而不是像通常那样传入下标并获得一个值。这个下标是数字且从 1 开始的(数组的第一个元素在索引 1 处),这与大多数编程语言使用的约定不同。该e(ie)的手段,我们要完全匹配,在不扩展像模式匹配字符*

如果在数组中找不到该值,${my_array[(ie)foo]则将计算为数组末尾之后的第一个索引,因此对于 3 元素数组,它将返回 4。${#my_array}给出数组最后一个元素的索引,因此如果前者小于或等于后者,则给定值存在于数组中的某处。如果要检查给定值是否不在数组中,请将“小于或等于”更改为“大于”:

[[ ${my_array[(ie)foo]} -gt ${#my_array} ]]
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 21

array=(foo bar baz foo)
pattern=f*
value=foo

if (($array[(I)$pattern])); then
  echo array contains at least one value that matches the pattern
fi

if (($array[(Ie)$value])); then
  echo value is amongst the values of the array
fi
Run Code Online (Sandbox Code Playgroud)

$array[(I)foo]返回最后一次出现fooin的索引,$array如果未找到则返回0。该e标志是为它是一个eXACT匹配,而不是一个模式匹配。

要检查$valueis 在一个字面值列表中,您可以将该值列表传递给一个匿名函数并在函数体中查找$valuein $@

if ()(( $@[(Ie)$value] )) foo bar baz and some more; then
  echo "It's one of those"
fi
Run Code Online (Sandbox Code Playgroud)

要知道该值在数组中出现的次数,您可以使用${A:*B}运算符(数组的元素A也在数组中B):

array=(foo bar baz foo)
value=foo
search=("$value")
(){print -r $# occurrence${2+s} of $value in array} "${(@)array:*search}"
Run Code Online (Sandbox Code Playgroud)