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
A dictionary's item is a value that is unambiguously associated with a unique key and the key is used to retrieve the item. The key can be of any type except a variant or an array (but generally it is a string or still an integer). The item can be of any type: integer, real, string, variant, object and so on.
Bash dictionaries give you hash maps and associative arrays in Linux shell scripts. We'll show you how to use these powerful and useful data structures in your own Linux shell scripts.
Bash supports one-dimensional numerically indexed and associative arrays types. Numerical arrays are referenced using integers, and associative are referenced using strings.
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")
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With