Bash associative array sorting by value

The best way to sort a bash associative array by VALUE is to NOT sort it.

Instead, get the list of VALUE:::KEYS, sort that list into a new KEY LIST, and iterate through the list.

declare -A ADDR
ADDR[192.168.1.3]="host3"
ADDR[192.168.1.1]="host1"
ADDR[192.168.1.2]="host2"

KEYS=$(
for KEY in ${!ADDR[@]}; do
  echo "${ADDR[$KEY]}:::$KEY"
done | sort | awk -F::: '{print $2}'
)

for KEY in $KEYS; do
  VAL=${ADDR[$KEY]}
  echo "KEY=[$KEY] VAL=[$VAL]"
done

output:
KEY=[192.168.1.1] VAL=[host1]
KEY=[192.168.1.2] VAL=[host2]
KEY=[192.168.1.3] VAL=[host3]

Alternatively you can sort the indexes and use the sorted list of indexes to loop through the array:

authors_indexes=( ${!authors[@]} )
IFS=$'\n' authors_sorted=( $(echo -e "${authors_indexes[@]/%/\n}" | sed -r -e 's/^ *//' -e '/^$/d' | sort) )

for k in "${authors_sorted[@]}"; do
  echo $k ' - ' ${authors["$k"]}
done 

Extending the answer from @AndrewSchulman, using -rn as a global sort option reverses all columns. In this example, authors with the same associative array value will be output by reverse order of name.

For example

declare -A authors
authors=( [Pushkin]=10050 [Gogol]=23 [Dostoyevsky]=9999 [Tolstoy]=23 )

for k in "${!authors[@]}"
do
  echo $k ' - ' ${authors["$k"]}
done | sort -rn -k3

will output

Pushkin  -  10050
Dostoyevsky  -  9999
Tolstoy  -  23
Gogol  -  23
Options for sorting specific columns can be provided after the column specifier. i.e. sort -k3rn

Note that keys can be specified as spans. Here -k3 happens to be fine because it is the final span, but to use only column 3 explicitly (in case further columns were added), it should be specified as -k3,3, Similarly to sort by column three in descending order, and then column one in ascending order (which is probably what is desired in this example):

declare -A authors
authors=( [Pushkin]=10050 [Gogol]=23 [Dostoyevsky]=9999 [Tolstoy]=23 )
for k in "${!authors[@]}"
do
  echo $k ' - ' ${authors["$k"]}
done | sort -k3,3rn -k1,1

will output

Pushkin  -  10050
Dostoyevsky  -  9999
Gogol  -  23
Tolstoy  -  23

You can easily sort your output, in descending numerical order of the 3rd field:

for k in "${!authors[@]}"
do
    echo $k ' - ' ${authors["$k"]}
done |
sort -rn -k3

See sort(1) for more about the sort command. This just sorts output lines; I don't know of any way to sort an array directly in bash.

I also can't see how the above can give you names ("Pushkin" et al.) as array keys. In bash, array keys are always integers.