Reputation: 877
With bash, it is possible to store an array in a dictionary? I have shown some sample code of fetching an array from the dictionary but it seems to lose the fact that it is an array.
I expect it is the dict+=(["pos"]="${array[@]}")
command but am unsure of how to do this or if it is even possible.
# Normal array behaviour (just an example)
array=(1 2 3)
for a in "${array[@]}"
do
echo "$a"
done
# Outputs:
# 1
# 2
# 3
# Array in a dictionary
declare -A dict
dict+=(["pos"]="${array[@]}")
# When I fetch the array, it is not an array anymore
posarray=("${dict[pos]}")
for a in "${posarray[@]}"
do
echo "$a"
done
# Outputs:
# 1 2 3
# but I want
# 1
# 2
# 3
Upvotes: 6
Views: 4308
Reputation: 295472
printf '%q '
+ eval
You can flatten your array into a string:
printf -v array_str '%q ' "${array[@]}"
dict["pos"]=$array_str
...and then use eval
to expand that array back:
# WARNING: Only safe if array was populated with eval-safe strings, as from printf %q
key=pos; dest=array
printf -v array_cmd "%q=( %s )" "$dest" "${dict[$key]}"
eval "$array_cmd"
Note that this is only safe if your associative array is populated through the code using printf '%q '
to escape the values before they're added; content that avoids this process is potentially unsafe to eval
.
Slower but safer (if you can't prevent modification of your dictionary's contents by untrusted code), another approach is to store a base64-encoded NUL-delimited list:
dict["pos"]=$(printf '%s\0' "${array[@]}" | openssl enc base64)
...and read it out the same way:
array=( )
while IFS= read -r -d '' item; do
array+=( "$item" )
done < <(openssl enc -d base64 <<<"${dict["pos"]}"
This one's actually symmetric, though it requires bash 4.3 or newer. That said, it restricts your key names to those which are permissible as shell variable names.
key=pos
array=( "first value" "second value" )
printf -v var_name 'dict_%q' "$key"
declare -n var="$var_name"
var=( "${array[@]}" )
unset -n var
...whereafter declare -p dict_pos
will emit declare -a dict_pos=([0]="first value" [1]="second value")
. On the other end, for retrieval:
key=pos
printf -v var_name 'dict_%q' "$key"
declare -n var="$var_name"
array=( "${var[@]}" )
unset -n var
...whereafter declare -p array
will emit declare -a array=([0]="first value" [1]="second value")
.
Upvotes: 4
Reputation: 361685
Dictionaries are associative arrays, so the question rephrased is: "Is it possible to store an array inside another array?"
No, it's not. Arrays cannot be nested.
dict+=(["pos"]="${array[@]}")
For this to work you'd need an extra set of parentheses to capture the value as an array and not a string:
dict+=(["pos"]=("${array[@]}"))
But that's not legal syntax.
Upvotes: 2