Bash: как назначить ассоциативный массив другому имени переменной (например, переименовать переменную)?
Мне нужно перебрать ассоциативный массив и слить его содержимое в массив temp (и выполнить некоторое обновление до значения).
Затем оставшееся содержимое первого массива должно быть отброшено, и я хочу назначить массив temp исходной переменной массива.
Код Sudo:
declare -A MAINARRAY
declare -A TEMPARRAY
... populate ${MAINARRAY[...]} ...
while something; do #Drain some values from MAINARRAY to TEMPARRAY
${TEMPARRAY["$name"]}=((${MAINARRAY["$name"]} + $somevalue))
done
... other manipulations to TEMPARRAY ...
unset MAINARRAY #discard left over values that had no update
declare -A MAINARRAY
MAINARRAY=${TEMPARRAY[@]} #assign updated TEMPARRAY back to MAINARRAY (ERROR HERE)
Ответы
Ответ 1
С ассоциативными массивами, я не считаю, что есть другой метод, кроме повторения
for key in "${!TEMPARRAY[@]}" # make sure you include the quotes there
do
MAINARRAY["$key"]="${TEMPARRAY["$key"]}"
# or: MAINARRAY+=( ["$key"]="${TEMPARRAY["$key"]}" )
done
Ответ 2
Копирование ассоциативных массивов напрямую невозможно в bash. Лучшим решением, вероятно, является, как уже указывалось, итерация по массиву и его копирование шаг за шагом.
Есть другое решение, которое я использовал для передачи переменных в функции. Вы можете использовать тот же метод для копирования ассоциативных массивов:
# declare associative array
declare -A assoc_array=(["key1"]="value1" ["key2"]="value2")
# convert associative array to string
assoc_array_string=$(declare -p assoc_array)
# create new associative array from string
eval "declare -A new_assoc_array="${assoc_array_string#*=}
# show array definition
declare -p new_assoc_array
Ответ 3
Этот однострочный экземпляр выполняет ассоциативную копию массива: MAINARRAY = TEMPARRAY
eval $(typeset -A -p TEMPARRAY|sed 's/ TEMPARRAY=/ MAINARRAY=/')
Ответ 4
Следуя как рекомендациям glenn jackman, так и ffeldhaus, вы можете создать функцию, которая может стать удобной:
function cp_hash
{
local original_hash_name="$1"
local copy_hash_name="$2"
local __copy__=$(declare -p $original_hash_name);
eval declare -A __copy__="${__copy__:$(expr index "${__copy__}" =)}";
for i in "${!__copy__[@]}"
do
eval ${copy_hash_name}[$i]=${__copy__[$i]}
done
}
Использование:
declare -A copy_hash_name
cp_hash 'original_hash_name' 'copy_hash_name'
Пример:
declare -A hash
hash[hello]=world
hash[ab]=cd
declare -A copy
cp_hash 'hash' 'copy'
for i in "${!copy[@]}"
do
echo "key : $i | value: ${copy[$i]}"
done
Выведет
key : ab | value: cd
key : hello | value: world
Ответ 5
расширяется Luca Borrione, который не работал у меня, и я отказался от попыток отследить проблему расширения eval - я столкнулся с различиями до и после bash 4.2. после 4.2 (что-то) это становится намного проще... но это не обратно совместимо. См. 1 и 2
поэтому моя вариация проверена на 4.1.2 (1) и 4.3.46 (1):
#!/bin/bash
## bash4 due to associative arrays!
function cp_hash() {
## REQUIRES you to declare -A $2 in advance.
local original_hash_name="$1"
local copy_hash_name="$2"
#
# sadly we have no way to identify if you have already declared it, so bull ahead.
#
## store the definition of the old array
local __copy__=$(declare -p $original_hash_name)
## rename the array inside the definition
__copy__=${__copy__/${original_hash_name}=/__copy__=}
## for bash 4.2 > we could end here.
## declare -A creates local scope variables by default, so add -g
## this DOES NOT work prior to 4.2, even w/o -g and w/ a declare outside.
# __copy__=${__copy__/${original_hash_name}=/${copy_hash_name}=}
# eval ${__copy__/-A/-g -A}
## for bash4 where we can't do -g, then:
## local associative array based on the definition we stored and modified
eval ${__copy__}
## loop through the local copy, and store it in the declared-outside copy.
for i in "${!__copy__[@]}"
do
eval ${copy_hash_name}[$i]=${__copy__[$i]}
done
}
declare -A hash
hash[hello]=world
hash[ab]=cd
#not required for 4.2+ if you use -g, neither helps nor hinders
declare -A copy
cp_hash 'hash' 'copy'
echo hash: ${hash[@]}
echo copy: ${copy[@]}
echo "copy result loop"
for i in "${!copy[@]}"
do
echo "key : $i | value: ${copy[$i]}"
done
Ответ 6
MAINARRAY=( "${TEMPARRAY[@]}" )