I have had so many instances where I wanted to check if a value was present in an array or not. You can probably iterate over all the array items and check it individually, but what if I give you the red pill?
I have created an array in which there is a string asdf
and I want to make sure if I really put it in the array or not. Following is how to check for the string asdf
in an array:
if [[ "${array[@]}" =~ 'asdf' ]]; then
echo "the string 'asdf' is in the array"
fi
The easiest method for checking if a value is present in a given that is to first expand the array such that all the elements are displayed, and then simply "grep" for it.
There are two ways you can "grep for it". Let's look at both of these methods.
Method 1: Use regex to check array value
By far, this is the easiest approach (at least in my opinion):
#!/usr/bin/env bash
array=('10' '00' '101')
if [[ "${array[@]}" =~ '101' ]]; then
echo "Found the number 5"
fi
In case you do not know, the @
operator in Bash, when substituted with a real index, just expands the entire array and "prints the whole array" (sort of). Then, a weird operator is used... The =~
operator.
This operator does not have a "formal name" in the official Bash document, but I like to call it the "regex operator". Since it is used for pattern matching.
With the help of the regex operator, I search for a specific pattern. Since each element (when "expanded" with the @
operator) is separated by spaces (it's bad, I know), we can easily search for a particular "word" that matches with an individual element.
This is how the current method of searching for a value in a Bash array works.
To prove that, below is the output one gets from running this script:
Found the number 5
Method 2: Use grep to see if array contains value
If it is too hard for you to remember what the regex operator is (I can understand, it was hard for me to remember in the beginning too), we can resort to some ugly hacks! :D
#!/usr/bin/env bash
array=('10' '00' '101')
if echo "${array[@]}" | grep '101' > /dev/null; then
echo "Found the number 5"
fi
What we are doing here is pretty much what the =~
operator did for us in the previous method. But here, we are doing something that one might do if they were on a command line.
We are literally printing every element of the array and checking for the existance of a pattern using the grep
utility.
We also put a handy little redirect to /dev/null
. This is beacause, if a match is found, the entire matching line will be printed to the STDOUT. You probably don't want that.
In our case, the return code of grep, if it found a match, will be 0. Otherwise it will be any other, non-zero number. This way, we can take advantage of a utility's exit code and use that as a condition in our if-statement.
For the above script, following is the expected output:
Found the number 5
More precised matching
As you might have notied in the warning at the top of this article, the above stated methods not only match the entire word for a pattern, but they can also match with a subset of a string. And then give a "pseudo success indication" that the value you are looking for is present, but in reality, it is not.
Let's take a look at what I am trying to warn you against.
#/usr/bin/env bash
array=('hello' 'world' 'randomwords1000101sandwhich')
if [[ "${array[@]}" =~ '1000101' ]]; then
echo "The number we were looking for, is present"
fi
And, let's run this to see what output this produces.
The number we were looking for, is present
Ouch! Yes, the value we are looking for is definitely present in the array, but that is not the "entire value". It matched a subset of an entire element! This is a side-effect. Let's deal with this effectively.
Method 3: Use loops to check array value (for exact match)
Time to run around in circles err, I mean loops!
#!/usr/bin/env bash
array=('hello' 'world' 'randomwords1000101sandwhich')
matched=false
for element in "${array[@]}"; do
if [[ "$element" == '1000101' ]]; then
matched=true;
fi
done
if [[ "$matched" == 'false' ]]; then
echo "The number you are looking for, is absent from the array... :("
else
echo "The number you are looking for, is present in the array; hoo_rray_"
fi
Here, instead of using any regex operator or the grep
tool itself, I do an exact match for every element of an array. I also use a "flag" variable (matched
) to check if the match actually occured or not.
I do this first, by looping over every element of the array. Then, by using the ==
operator to check if the exact string is present or not. If present, I set the value of our flag variable (matched
) as true
, since we did find a match :)
Finally, I have a simple if condition which prints the result.
I get the following output:
The number you are looking for, is absent from the array... :(
Conclusion
In this article, I go over three methods that you can use to check for a value in a Bash array.
The first two methods are to expand the entire array and perform a regular expression match, which can be error-prone, if not done correctly.
The final method is to iterate over all elements and check for an exact match. This last method is for when you need to find an exact match, for confirmation.
I presonally perfer the regex match, but I also use the exact match method when I see the Bat-Signal! (Yes, I'm Batman!)