Bash: Dictionaries
Dictionaries, also called associative arrays, store values using named keys instead of numeric indexes. They are useful when each value has a meaningful name.
Creating a Dictionary
Declare an associative array
declare -A user Use declare -A to create an associative array. The -A option tells Bash that the array uses string keys. Associative arrays are available in Bash 4 and later.
Create a dictionary with initial values
declare -A user=(
[name]="Alex"
[shell]="bash"
[editor]="vim"
) Keys are written inside square brackets and assigned values with =. Quote values that contain spaces or other characters that the shell could interpret.
CRUD Operations
Create or add a key-value pair
user[timezone]="UTC"Assigning a value to a new key adds that key to the dictionary. Assigning another value to the same key replaces the old value.
Read a value
echo "Shell: ${user[shell]}"Put the key inside square brackets when reading a value. Always quote the expansion when its value may contain spaces.
Update a value
user[editor]="nano" Updating a dictionary entry uses the same assignment syntax as creating one. The existing value for editor is replaced.
Delete a key-value pair
unset 'user[timezone]' Use unset with the quoted array reference to remove one entry. Quoting prevents the shell from treating special characters in a key as syntax.
Inspecting a Dictionary
Check whether a key exists
if [[ -v user[shell] ]]; then
echo "The shell is ${user[shell]}"
fi The -v conditional checks whether an array element has been set. This distinguishes an existing key with an empty value from a key that does not exist.
List all keys and values
for key in "${!user[@]}"; do
printf '%s: %s\n' "$key" "${user[$key]}"
done The ! expansion returns all keys. Associative arrays do not guarantee a particular iteration order, so do not rely on the order in which entries are printed.
Real Usage: Processing Script Parameters
Use a dictionary to parse named parameters
#!/usr/bin/env bash
declare -A options=(
[name]="Guest"
[color]="blue"
)
for argument in "$@"; do
case "$argument" in
--name=*)
options[name]="${argument#*=}"
;;
--color=*)
options[color]="${argument#*=}"
;;
--help)
printf 'Usage: %s [--name=NAME] [--color=COLOR]\n' "$0"
exit 0
;;
*)
printf 'Unknown parameter: %s\n' "$argument" >&2
exit 1
;;
esac
done
printf 'Hello, %s!\n' "${options[name]}"
printf 'Your selected color is %s.\n' "${options[color]}" The --color=* pattern matches any argument that starts with --color=. In ${argument#*=}, the #*= expansion removes the shortest prefix ending at the first =, leaving only the value supplied by the user. For example, --color=green stores green in options[color].
Save this as greet.sh, make it executable with chmod +x greet.sh, and run it with ./greet.sh --name=Sam --color=green. The dictionary keeps related options together while the case statement validates and stores each named parameter.
Why use a dictionary here?
A dictionary makes the script easier to extend: adding another option only requires a default entry and another case branch. Later code can read options[name] or options[color] without depending on the order of positional parameters.