Check if a Bash array contains a value
In Bash, what is the simplest way to test if an array contains a certain value?
Solution 1:
This approach has the advantage of not needing to loop over all the elements (at least not explicitly). But since array_to_string_internal()
in array.c still loops over array elements and concatenates them into a string, it's probably not more efficient than the looping solutions proposed, but it's more readable.
if [[ " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array contains value
fi
if [[ ! " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array doesn't contain value
fi
Note that in cases where the value you are searching for is one of the words in an array element with spaces, it will give false positives. For example
array=("Jack Brown")
value="Jack"
The regex will see "Jack" as being in the array even though it isn't. So you'll have to change IFS
and the separator characters on your regex if you want still to use this solution, like this
IFS="|"
array=("Jack Brown${IFS}Jack Smith")
value="Jack"
if [[ "${IFS}${array[*]}${IFS}" =~ "${IFS}${value}${IFS}" ]]; then
echo "true"
else
echo "false"
fi
unset IFS # or set back to original IFS if previously set
This will print "false".
Obviously this can also be used as a test statement, allowing it to be expressed as a one-liner
[[ " ${array[*]} " =~ " ${value} " ]] && echo "true" || echo "false"
Solution 2:
Below is a small function for achieving this. The search string is the first argument and the rest are the array elements:
containsElement () {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
A test run of that function could look like:
$ array=("something to search for" "a string" "test2000")
$ containsElement "a string" "${array[@]}"
$ echo $?
0
$ containsElement "blaha" "${array[@]}"
$ echo $?
1
Solution 3:
One-line solution
printf '%s\n' "${myarray[@]}" | grep -F -x 'myvalue'
More thorough one-line solution:
# If your array items contain line breaks, delimit on null chars instead:
printf '%s\0' "${myarray[@]}" | grep -F -x -z 'myvalue'
Explanation
The printf
statement prints each element of the array on a separate line (or in the case of %s\0
, it prints a null character between each array item).
The grep
statement uses the following flags to match a line that contains exactly the string given as myvalue
(no more, no less):
-
-F
/--fixed-strings
- Interpret PATTERNS as fixed strings, not regular expressions. -
-x
/--line-regexp
- Select only those matches that exactly match the whole line.
Usage
To put this into an if ... then
statement:
if printf '%s\n' "${myarray[@]}" | grep -Fxq 'myvalue'; then
# ...
fi
I added a -q
flag to the grep
expression so that it won't print matches; it will just treat the existence of a match as "true."
Update: Thanks, Tino, for pointing out the case where newlines can exist within array items.
Solution 4:
for i in "${array[@]}"
do
if [ "$i" -eq "$yourValue" ] ; then
echo "Found"
fi
done
For strings:
for i in "${array[@]}"
do
if [ "$i" == "$yourValue" ] ; then
echo "Found"
fi
done