How do I check whether a zsh array contains a given value?

If you have an array $my_array and you want to know whether it contains the string foo, one possible test is

[[ ${my_array[(ie)foo]} -le ${#my_array} ]]

The full, exact value of the array element must be foo; it’s not a substring check or anything like that.

If you want to see whether the value of the variable $my_string is in the array, use

[[ ${my_array[(ie)$my_string]} -le ${#my_array} ]]

This (ie) syntax isn’t very obvious. It’s explained in the Subscript Flags section of the ZSH manual. The i part means that we are using “reverse subscripting”: instead of passing in a subscript and obtaining a value, like we do with the usual ${my_array[1]}, we’re passing a value and asking for the first subscript that would give this value. This subscript is numerical and 1-based (the first element of the array is at index 1), which is different from the convention used by most programming languages. The e in (ie) means that we want an exact match, without expanding pattern-matching characters like *.

If the value is not found in the array, ${my_array[(ie)foo] will evaluate to the first index past the end of the array, so for a 3-element array it would return 4. ${#my_array} gives the index of the last element of the array, so if the former is less than or equal to the latter then the given value is present in the array somewhere. If you want to check whether a given value is not in the array then change the “less than or equal to” to a “greater than”:

[[ ${my_array[(ie)foo]} -gt ${#my_array} ]]

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

$array[(I)foo] returns the index of the last occurrence of foo in $array and 0 if not found. The e flag is for it to be an exact match instead of a pattern match.

To check the $value is among a literal list of values, you could pass that list of values to an anonymous function and look for the $value in $@ in the body of the function:

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

To know how many times the value is found in the array, you could use the ${A:*B} operator (elements of array A that are also in array B):

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

Tags:

Zsh