5

Suppose I have a non-associative array that has been defined like

my_array=(foo bar baz)

How can I check whether the array contains a given string? I’d prefer a solution that can be used within the conditional of an if block (e.g. if contains($my_array, "something"); then ...).

8

If you have an array $my_array and you want to know whether it contains the string foo, the 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} ]]
6
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 know how many times the value is found in the array, you could use 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}"
  • there is a closing brace missing in the first if (edit remains below the 6 character minimum …): if ((${array[(I)$pattern]})); then – pseyfert May 18 at 10:03
  • @pseyfert, thanks. Fixed now. I opted for removing the {...} which makes it more legible. They are not necessary in zsh like in csh/rc/tcl/perl but unlike in ksh/bash/yash. – Stéphane Chazelas May 18 at 11:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.