7

I declare an associative array:

declare -A array=([a]=blue [b]=red [c]=yellow)

now I can do:

echo ${array[@]}  --> blue red yellow

or

echo ${array[b]}  --> red

or

echo ${!array[@]} --> a b c

Now I want to know only the key associated to red value. Is there a way to detect just a single key?

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
pietro letti
  • 419
  • 1
  • 5
  • 11

3 Answers3

6

Assuming that you'd want to get a list of keys that correspond to a particular value, and that you'd like to store this list in an array:

#!/bin/bash

declare -A hash
hash=(
    [k1]="hello world"
    [k2]="hello there"
    [k3]="hello world"
    [k4]=bumblebees
)

string="hello world"

keys=()
for key in "${!hash[@]}"; do
    if [[ ${hash[$key]} == "$string" ]]; then
        keys+=( "$key" )
    fi
done

printf 'Keys with value "%s":\n' "$string"
printf '\t%s\n' "${keys[@]}"

This walks through the list of keys and tests the value corresponding to each key against the string we're looking for. If there is a match, we store the key in the keys array.

At the end, the found keys are outputted.

The output of this script would be

Keys with value "hello world":
        k1
        k3
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
2

The zsh shell (note that zsh had associative array support decades before bash) has operators for that:

  • ${hash[(R)pattern]} expands to the values that match the pattern.
  • ${(k)hash[(R)pattern]} expands to the keys where the corresponding value matches the pattern.
  • ${(k)hash[(Re)string]} same except the string is treated as an exact string, not a pattern even if it contains wildcard characters.

So:

print -r -- ${(k)array[(Re)red]}

Will print the non-empty keys where the value is red.

To include the empty keys, use:

$ typeset -A array
$ array=(a blue b red c yellow '' red)
$ printf '<%s>\n' "${(@k)array[(Re)red]}"
<>
<b>
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
1

It's not pretty but you could do:

for k in "${!array[@]}"; do
    [[ ${array[$k]} == red ]] && printf '%s\n' "$k"
done

This will loop through the indices of the array and check each if their value is red, if so it will print the index.

Alternatively and also not pretty you could use sed:

declare -p array | sed -n 's/.*\[\(.*\)\]="red".*/\1/p'

This will print the array as declared and find the index for the value of red and print that.

jesse_b
  • 35,934
  • 12
  • 91
  • 140