Test if element is in array in bash
Solution 1
In Bash 4, you can use associative arrays:
# set up array of constants
declare -A array
for constant in foo bar baz
do
array[$constant]=1
done
# test for existence
test1="bar"
test2="xyzzy"
if [[ ${array[$test1]} ]]; then echo "Exists"; fi # Exists
if [[ ${array[$test2]} ]]; then echo "Exists"; fi # doesn't
To set up the array initially you could also do direct assignments:
array[foo]=1
array[bar]=1
# etc.
or this way:
array=([foo]=1 [bar]=1 [baz]=1)
Solution 2
It's an old question, but I think what is the simplest solution has not appeared yet: test ${array[key]+_}
. Example:
declare -A xs=([a]=1 [b]="")
test ${xs[a]+_} && echo "a is set"
test ${xs[b]+_} && echo "b is set"
test ${xs[c]+_} && echo "c is set"
Outputs:
a is set
b is set
To see how this work check this.
Solution 3
There is a way to test if an element of an associative array exists (not set), this is different from empty:
isNotSet() {
if [[ ! ${!1} && ${!1-_} ]]
then
return 1
fi
}
Then use it:
declare -A assoc
KEY="key"
isNotSet assoc[${KEY}]
if [ $? -ne 0 ]
then
echo "${KEY} is not set."
fi
Solution 4
You can see if an entry is present by piping the contents of the array to grep.
printf "%s\n" "${mydata[@]}" | grep "^${val}$"
You can also get the index of an entry with grep -n, which returns the line number of a match (remember to subtract 1 to get zero-based index) This will be reasonably quick except for very large arrays.
# given the following data
mydata=(a b c "hello world")
for val in a c hello "hello world"
do
# get line # of 1st matching entry
ix=$( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 )
if [[ -z $ix ]]
then
echo $val missing
else
# subtract 1. Bash arrays are zero-based, but grep -n returns 1 for 1st line, not 0
echo $val found at $(( ix-1 ))
fi
done
a found at 0
c found at 2
hello missing
hello world found at 3
explanation:
$( ... )
is the same as using backticks to capture output of a command into a variableprintf
outputs mydata one element per line- (all quotes necessary, along with
@
instead of*.
this avoids splitting "hello world" into 2 lines) grep
searches for exact string:^
and$
match beginning and end of linegrep -n
returns line #, in form of 4:hello worldgrep -m 1
finds first match onlycut
extracts just the line number- subtract 1 from returned line number.
You can of course fold the subtraction into the command. But then test for -1 for missing:
ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))
if [[ $ix == -1 ]]; then echo missing; else ... fi
$(( ... ))
does integer arithmetic
Solution 5
#!/bin/bash
function in_array {
ARRAY=$2
for e in ${ARRAY[*]}
do
if [[ "$e" == "$1" ]]
then
return 0
fi
done
return 1
}
my_array=(Drupal Wordpress Joomla)
if in_array "Drupal" "${my_array[*]}"
then
echo "Found"
else
echo "Not found"
fi
Related videos on Youtube

Tgr
Updated on September 17, 2022Comments
-
Tgr 9 months
Is there a nice way of checking if an array has an element in bash (better than looping through)?
Alternatively, is there another way to check if a number or string equals any of a set of predefined constants?
-
Tgr over 12 yearsIt is a nice solution when the constants are alphanumeric, though (with
grep "\b$FINDME\b"
). Probably could work with non-alphanumeric constants that have no spaces, with"(^| )$FINDME(\$| )"
(or something like that... I have never been able to learn what flavor of regexp grep uses.) -
haridsv about 12 yearsActually, the [[]] test doesn't work in the case the value is empty. E.g., "array['test']=''". In this case, the key 'test' exists, and you can see it listed with ${!array[@]}, but "[[ ${array['test']} ]]; echo $?" echoes 1, not 0.
-
Diego Fernández Durán over 11 yearsAssociative arrays were introduced in Bash 4.
-
tokland about 11 years
${array[$test1]}
is simple but has a problem: it won't work if you useset -u
in your scripts (which is recommended), as you'd get "unbound variable". -
Dennis Williamson about 11 years@tokland: Who recommends it? I certainly don't.
-
tokland about 11 years@DennisWilliamson: Ok, some people recommend it, but I think it would be nice to have a solution that works regardless the value of these flags.
-
tokland about 11 years
-
tokland about 11 yearsnote that
if ! some_check then return 1
=some_check
. So:isNotSet() { [[ ... ]] }
. Check my solution below, you can do it in a simple check. -
Adam D. over 7 yearsThe info manual recommneds you to use
env
to avoid ambiguities in aliases, progs and other functions that may have adopted the name "test". As aboveenv test ${xs[a]+_} && echo "a is set"
. You can also get this functionality using double-brackets, the same trick then checking for null:[[ ! -z "${xs[b]+_}" ]] && echo "b is set"
-
bertieb over 5 yearsCan you elaborate on why you are suggesting this approach? OP asked if there is a way to do it without looping through the array, which is what you are doing in
in_array
. Cheers -
Tobias over 4 yearsWell, at least that loop is capsuled in a function, which might be good enough for many cases (with small data sets), and doesn't require bash 4+. Probably
${ARRAY[@]}
should be used. -
Arne L. almost 4 yearsAlso you can use the even simpler
[[ ${xs[b]+set} ]]