Issue
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?
Solution
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
Answered By - pmf Answer Checked By - Katrina (WPSolving Volunteer)