Используя Bash, возможно ли сохранить массив в словаре - PullRequest
0 голосов
/ 07 мая 2018

С помощью bash можно хранить массив в словаре? Я показал некоторый пример кода извлечения массива из словаря, но он, похоже, теряет тот факт, что это массив.

Я ожидаю, что это команда dict+=(["pos"]="${array[@]}"), но не знаю, как это сделать или возможно ли это.

# 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

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Нет, но есть обходные пути.


Использование printf '%q ' + eval

Вы можете объединить ваш массив в строку:

printf -v array_str '%q ' "${array[@]}"
dict["pos"]=$array_str

... и затем используйте eval, чтобы развернуть этот массив обратно:

# 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"

Обратите внимание, что это безопасно только в том случае, если ваш ассоциативный массив заполняется кодом, используя printf '%q ' для экранирования значений перед их добавлением; контент, который избегает этого процесса, потенциально небезопасен для eval.


Использование кодировки base64

Медленнее, но безопаснее (если вы не можете предотвратить изменение содержимого вашего словаря ненадежным кодом), другой подход заключается в сохранении списка, закодированного в NULL, с кодировкой NUL:

dict["pos"]=$(printf '%s\0' "${array[@]}" | openssl enc base64)

... и прочитайте это так же:

array=( )
while IFS= read -r -d '' item; do
  array+=( "$item" )
done < <(openssl enc -d base64 <<<"${dict["pos"]}"

Использование нескольких переменных + косвенное расширение

Это на самом деле симметрично, хотя для этого требуется bash 4.3 или новее. Тем не менее, он ограничивает имена ваших ключей теми, которые допустимы в качестве имен переменных оболочки.

key=pos
array=( "first value" "second value" )

printf -v var_name 'dict_%q' "$key"
declare -n var="$var_name"
var=( "${array[@]}" )
unset -n var

... после чего declare -p dict_pos будет излучать declare -a dict_pos=([0]="first value" [1]="second value"). С другой стороны, для поиска:

key=pos
printf -v var_name 'dict_%q' "$key"
declare -n var="$var_name"
array=( "${var[@]}" )
unset -n var

... после чего declare -p array будет излучать declare -a array=([0]="first value" [1]="second value").

0 голосов
/ 07 мая 2018

Словари являются ассоциативными массивами, поэтому перефразируемый вопрос: «Можно ли хранить массив внутри другого массива?»

Нет, это не так. Массивы не могут быть вложенными.

dict+=(["pos"]="${array[@]}")

Чтобы это работало, вам понадобится дополнительный набор скобок для захвата значения в виде массива, а не строки:

dict+=(["pos"]=("${array[@]}"))

Но это недопустимый синтаксис.

...