Подтвердить что ты не робот

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)
4b9b3361

Ответ 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[@]}" )