I have something in bash
like
myArray=(\'red\' \'orange\' \'green\')
And I would like to do something like
echo ${
You must declare your array before use with
declare -A myArray
myArray=([red]=1 [orange]=2 [green]=3)
echo ${myArray['orange']}
In zsh you can do
xs=( foo bar qux )
echo ${xs[(ie)bar]}
see zshparam(1) subsection Subscript Flags
This will do it:
#!/bin/bash
my_array=(red orange green)
value='green'
for i in "${!my_array[@]}"; do
if [[ "${my_array[$i]}" = "${value}" ]]; then
echo "${i}";
fi
done
Obviously, if you turn this into a function (e.g. get_index() ) - you can make it generic
No. You can only index a simple array with an integer in bash
. Associative arrays (introduced in bash
4) can be indexed by strings. They don't, however, provided for the type of reverse lookup you are asking for, without a specially constructed associative array.
$ declare -A myArray
$ myArray=([red]=0 [orange]=1 [green]=2)
$ echo ${myArray[green]}
2
This is just another way to initialize an associative array as chepner showed.
Don't forget that you need to explicitly declare
or typset an associative array with -A
attribute.
i=0; declare -A myArray=( [red]=$((i++)) [orange]=$((i++)) [green]=$((i++)) )
echo ${myArray[green]}
2
This removes the need to hard code values and makes it unlikely you will end up with duplicates.
If you have lots of values to add it may help to put them on separate lines.
i=0; declare -A myArray;
myArray+=( [red]=$((i++)) )
myArray+=( [orange]=$((i++)) )
myArray+=( [green]=$((i++)) )
echo ${myArray[green]}
2
Say you want an array of numbers and lowercase letters (eg: for a menu selection) you can also do something like this.
declare -a mKeys_1=( {{0..9},{a..z}} );
i=0; declare -A mKeys_1_Lookup; eval mKeys_1_Lookup[{{0..9},{a..z}}]="$((i++))";
If you then run
echo "${mKeys_1[15]}"
f
echo "${mKeys_1_Lookup[f]}"
15
Another tricky one-liner:
index=$((-1 + 10#0$(IFS=$'\n' echo "${my_array[*]}" | grep --line-number --fixed-strings -- "$value" | cut -f1 -d:)))
features:
-1
when not foundcaveats:
value
to be non-emptyExplanations by breaking it down in execution order:
IFS=$'\n' echo "${my_array[*]}"
set array expansion separator (IFS
) to a new line char & expand the array
grep --line-number --fixed-strings -- "$value"
grep for a match:
--line-number
or -n
)--fixed-strings
or -F
; disables regex)allow for elements starting with a -
(--
)
cut -f1 -d:
extract only the line number (format is <line_num>:<matched line>
)
$((-1 + 10#0$(...)))
subtract 1 since line numbers are 1-indexed and arrays are 0-indexed
if $(...)
does not match:
0
is used (10#0
)$(...)
matches:
10#0
; i.e. 10#02
, 10#09
, 10#014
, etc10#
prefix forces base-10/decimal numbers instead of octalUsing awk
instead of grep
, cut
& bash arithmetic:
IFS=$'\n'; awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}" <<< "${my_array[*]}"
features:
caveats:
when not foundExplanations by breaking it down in execution order:
IFS=$'\n' [...] <<< "${my_array[*]}"
set array expansion separator (IFS
) to a new line char & expand the array
awk "\$0 == \"${value//\"/\\\"}\" {print NR-1}"
match the entire line & print the 0-indexed line number
${value//\"/\\\"}
replaces double quotes in $value
with escaped versions