Maybe an associative array is not the best tool here, you could do:
#! /bin/bash - export TZ while IFS=: read -r region TZ; do printf '%s: %(%H:%M%p, %A, %d %B, %Y)T\n' "$region" -2 done << 'EOF' Chile:America/Santiago Tierra Del Fuego:America/Argentina/Ushuaia ... EOF Note that -2 for bash printf's %T format directive refers to the time that bash instance was started. That makes sure you get an output for the same time in all regions even if you started the script at 10:46:59.9 and it takes over 0.1 seconds¹ to run.
You can iterate over the keys of an associative arrays in bash with:
for key in "${!assoc[@]}"; do value=${assoc[$key]} ... done But beware the order is non-deterministic.
In zsh², you can get both keys and values at the same time with:
for key value in "${(kv@)assoc}"; do ... done But there as well, the order is non-deterministic.
Associative arrays are useful to look-up individual values efficiently. There's a higher cost upon assignment as a hash table needs to be built, but the look up is efficient. Here, as you want to loop once over all entries, that completely defeats the purpose and becomes significantly worse both functionally and performance-wise. A normal array would make more sense.
In zsh:
list=( 'Chile' America/Santiago 'Tierra Del Fuego' America/Argentina/Ushuaia ) for zoneregion TZ in $list; do ... done Bash doesn't support looping with more than one variable, but you can do:
for (( i = 0; i < ${#list[@]}; i += 2 )); do zone=$region=${list[i]} TZ=${list[i+1]} ... done Instead there. Or:
set -- "${list[@]}" while (( $# )); do zone=$1region=$1 TZ=$2 ... shift 2 done But that's more cumbersome to write than the CSV heredoc approach mentioned above. Instead of a here doc, you could also have the CSV with the mapping in a separate file which could be maintained separately from the script, and use < /path/to/that/file instead of << 'EOF'...EOF.
¹ Or hours for instance because it's piped to a command that doesn' read its input in a while.
² Where the equivalent of bash printf's %T would be via its strftime builtin (and the $EPOCHSECONDS variable) or prompt expansion like with print -rP -- "$zone"$region %D{...}" (though only for the current time with the latter).