How to keep associative array order?
My approach is to create a sorted array of keys first:
keys=( $( echo ${!dict[@]} | tr ' ' $'\n' | sort ) )
for k in ${keys[@]}; do
echo "$k=${dict[$k]}"
done
As already pointed out, there is no mistake. Associative arrays are stored in a 'hash' order. If you want ordering, you don't use associative arrays. Or, you use a non-associative array as well as an associative array.
Keep a second (non-associative) array that identifies the keys in the order that they're created. Then step through the second array, using its contents to key the first (associative) array when printing the data. Like this:
declare -A groups; declare -a orders;
groups["group1"]="123"; orders+=( "group1" )
groups["group2"]="456"; orders+=( "group2" )
groups["group3"]="789"; orders+=( "group3" )
groups["group4"]="abc"; orders+=( "group4" )
groups["group5"]="def"; orders+=( "group5" )
# Convoluted option 1
for i in "${!orders[@]}"
do
echo "${orders[$i]}: ${groups[${orders[$i]}]}"
done
echo
# Convoluted option 1 - 'explained'
for i in "${!orders[@]}"
do
echo "$i: ${orders[$i]}: ${groups[${orders[$i]}]}"
done
echo
# Simpler option 2 - thanks, PesaThe
for i in "${orders[@]}"
do
echo "$i: ${groups[$i]}"
done
The 'simpler option 2' was suggested by PesaThe in a comment, and should be used in preference to the 'convoluted option'.
Sample output:
group1: 123
group2: 456
group3: 789
group4: abc
group5: def
0: group1: 123
1: group2: 456
2: group3: 789
3: group4: abc
4: group5: def
group1: 123
group2: 456
group3: 789
group4: abc
group5: def
You probably don't want to have two statements per line like that, but it emphasizes the parallelism between the handling of the two arrays.
The semicolons after the assignments in the question are not really necessary (though they do no active harm, beyond leaving the reader wondering 'why?').