Reputation: 955
According to man bash
it is possible to assign an associative array with a flat list of key-value pairs:
[…] or a list of words that is interpreted as a sequence of alternating keys and values: name=( key1 value1 key2 value2 ...)
This does work, but it does not work to use an array to get these "alternating keys and values":
name=( "${someArray[@]}" )
Consider this example:
#!/usr/bin/env bash
set -u
#declare -A map=(one ONE two TWO)
array=(one ONE two TWO)
declare -A map=("${array[@]}")
# Workaround with `eval`:
#eval "declare -A map=(${array[@]@Q})"
echo "KEYS:"
printf ' %s\n' "${!map[@]}"
echo "VALUES:"
printf ' %s\n' "${map[@]}"
echo "${#map[@]}"
Actual output:
KEYS:
one ONE two TWO
VALUES:
Expected output:
KEYS:
two
one
VALUES:
TWO
ONE
Why is that so?
Upvotes: 6
Views: 159
Reputation: 36058
Include the array parens in the quoted string to preserve the whitespace between items for the declaration. Also, if keys or values themselves contain whitespace, use @Q
to quote each item:
array=(one 'O NE' 'tw o' TWO)
declare -A map="(${array[@]@Q})"
echo "KEYS:"
printf ' %s\n' "${!map[@]}"
echo "VALUES:"
printf ' %s\n' "${map[@]}"
echo "${#map[@]}"
KEYS:
one
tw o
VALUES:
O NE
TWO
2
Tested with GNU bash 5.2.21
Upvotes: 6