bash associate array map hash - ghdrako/doc_snipets GitHub Wiki

Associative Arrays - since Bash 4 was released

Declare

declare -A myhash # MUST do this, or `local -A` or `readonly -A`

Assign

# Assign to it, note no "+"
###myhash=(bar) # Error: needs subscript when assigning associative array
myhash[a]='foo' # Insertion 1, not 0...sort of
myhash[b]='bar' # Insertion 2
myhash[c]='baz' # Insertion 3
myhash[d]='three' # 4 Different than our list example
myhash[e]='four' # Insertion 5, note, not 4
myhash[f]='five by five' # 6 Note spaces
myhash[g]='six' # Insertion 7
# OR
myhash=([a]=foo [b]=bar [c]=baz [d]="three" [e]="four" [f]="five by five" [g]="six")

Accessing

declare -a score
score[alex]="1"
score[edson]="2"
score[sebi]="3"
unset score[alex] # Delete alex entry
echo ${!score[@]} # alex edson sebi
echo ${score[@]} # 2 1 3
echo ${#score[@]} # 3
$ declare -A fullNames
$ fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
$ echo "Current user is: $USER.  Full name: ${fullNames[$USER]}."
Current user is: lhunath.  Full name: Maarten Billemont.

Display or dump the details and values

echo -e "\nThe key count is: ${#myhash[@]} or ${#myhash[*]}"
echo -e "\nThe length of the value of key [e] is: ${#myhash[e]}"
echo -e "\nDump or list:"
declare -p myhash | $FORMAT
echo -n "\${myhash[@]} = " ; printf "%q|" ${myhash[@]}
echo -en "\n\${myhash[*]} = " ; printf "%q|" ${myhash[*]}
echo -en "\n\"\${myhash[@]}\" = " ; printf "%q|" "${myhash[@]}"
echo -en "\n\"\${myhash[*]}\" = " ; printf "%q|" "${myhash[*]}"
echo -e " # Broken!" # Previous line is bad and no newline
# See `help printf` or chapter 6 "printf for reuse or debugging", we need
# this to show the correct words:
# %q quote the argument in a way that can be reused as shell input

We can print the contents of an associative array very much like we did with regular arrays:

$ declare -A dict
$ dict[astro]="Foo Bar"
$ declare -p dict
declare -A dict='([astro]="Foo Bar")'

With the same syntax as for indexed arrays, you can iterate over the keys (indices) of associative arrays:

$ for user in "${!fullNames[@]}"
> do echo "User: $user, full name: ${fullNames[$user]}."; done
User: lhunath, full name: Maarten Billemont.
User: greycat, full name: Greg Wooledge.

Iterate

echo -e "\nforeach \"\${!myhash[@]}\":"
for key in "${!myhash[@]}"; do
  echo -e "\tKey: $key; value: ${myhash[$key]}"
done
numbers=(1 2 3 4 5)
for ((i=0; i<${numbers[@]}; i++)); do
  numbers[i]=$((numbers[i] + 2))
done

Slice

# Handle slices (subsets) of the hash
echo -e "\nStart from hash insertion element 5 and show a slice of 2 elements:"
printf "%q|" "${myhash[@]:5:2}"
echo '' # No newline in above
echo -e "\nStart from hash insertion element 0 (huh?) and show a slice of 3 elements:"
printf "%q|" "${myhash[@]:0:3}"
echo '' # No newline in above
echo -e "\nStart from hash insertion element 1 and show a slice of 3 elements:"
printf "%q|" "${myhash[@]:1:3}"
echo '' # No newline in above

Delete keys

FORMAT='fmt --width 70 --split-only'
echo -e "\nDelete key c using unset (dumped before and after):"
declare -p myhash | $FORMAT
unset -v 'myhash[c]'
declare -p myhash | $FORMAT

Delete the entire hash

unset -v myhash

"Join" the values

function Join { local IFS="$1"; shift; echo "$*"; } # One character delimiter!
# Note the Join above requires "$*" and not "$@"!
echo -en "\nJoin ',' \${myhash[@]} = " ; Join ',' "${myhash[@]}"
function String_Join {
local delimiter="$1"
local first_element="$2"
shift 2
printf '%s' "$first_element" "${@/#/$delimiter}"
# Print first element, then reuse the '%s' format to display the rest of
# the elements (from the function args $@), but add a prefix of $delimiter
# by "replacing" the leading empty pattern (/#) with $delimiter.
}
echo -n "String_Join '<>' \${myhash[@]} = " ; String_Join '<>' "${myhash[@]}"

Word count

declare -A myhash
# Read the word list into a hash from $WORD_FILE
while read line; do
(( myhash[$line]++ ))
done < $WORD_FILE

echo -e "\nUnique words from: $WORD_FILE"
for key in "${!myhash[@]}"; do
echo "$key"
done | sort
echo -e "\nWord counts, ordered by word, from: $WORD_FILE"
for key in "${!myhash[@]}"; do
printf "%s\t%d\n" $key ${myhash[$key]}
done | sort
echo -e "\nWord counts, ordered by count, from: $WORD_FILE"
for key in "${!myhash[@]}"; do
printf "%s\t%d\n" $key ${myhash[$key]}
done | sort -k2,2n