I want to loop over the keys of an associative array, but I would like my script to work in zsh and bash. Would there be a way of doing it (syntax) that it would work in both
I know this
zsh:
for k in "${(k)array[@]}" do echo $k; done
bash:
for k in "${!array[@]}" do echo $k; done
Btw. I actually use oh-my-zsh, so I cannot really use something as emulate ksh
, because it makes my terminal crash.
You can wrap each implementation in a function, and define only the function appropriate to the current shell:
if [[ $ZSH_VERSION ]]; then
keys_for_array() {
local array=$1 dest=$2
[[ $1 && $2 ]] || { echo "Usage: keys_for_array source-array dest-array" >&2; return 1; }
: ${(AP)dest::=${(kP)array}}
}
elif [[ $BASH_VERSION && ! $BASH_VERSION =~ ^([123][.]|4[.][012]) ]]; then
keys_for_array() {
[[ $1 && $2 ]] || { echo "Usage: keys_for_array source-array dest-array" >&2; return 1; }
local -n array=$1 dest=$2
eval 'dest=( "${!array[@]}" )'
}
else
keys_for_array() { echo "ERROR: keys_for_array not available for this shell" >&2; return 1; }
fi
[[ $ZSH_VERSION ]] && typeset -A aa=( 1 one 2 two )
[[ $BASH_VERSION ]] && declare -A aa=( [1]=one [2]=two )
keys_for_array aa aak
declare -p aak
...when run on bash, output is:
declare -a aak=([0]="1" [1]="2")
...when run on zsh, output is:
typeset -a aak=( 1 2 )
In either case, you can then iterate over them:
keys_for_array aa aak
for key in "${aak[@]}"; do
echo "Key $key has value ${aa[$key]}"
done
Note that above, both functions are syntactically valid in both shells. Otherwise, it might be necessary to use eval
or source
to pull them in only conditionally. Personally, I would create two separate files with both bash and zsh versions of your portability library, and source only the file appropriate to the current shell.