Как переименовать ассоциативный массив в Bash? - PullRequest
16 голосов
/ 12 июля 2011

Мне нужно перебрать ассоциативный массив и слить его содержимое во временный массив (и выполнить некоторое обновление до значения).

Затем оставшееся содержимое первого массива следует отбросить, и яхотите назначить временный массив исходной переменной массива.

Код 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)

Ответы [ 8 ]

23 голосов
/ 16 января 2012

Копирование ассоциативных массивов в 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
12 голосов
/ 12 июля 2011

С ассоциативными массивами я не верю, что есть какой-либо другой метод, кроме итерации

for key in "${!TEMPARRAY[@]}"  # make sure you include the quotes there
do
  MAINARRAY["$key"]="${TEMPARRAY["$key"]}"
  # or: MAINARRAY+=( ["$key"]="${TEMPARRAY["$key"]}" )
done
7 голосов
/ 23 сентября 2013

Этот однострочный делает копию ассоциативного массива: MAINARRAY = TEMPARRAY

eval $(typeset -A -p TEMPARRAY|sed 's/ TEMPARRAY=/ MAINARRAY=/')
2 голосов
/ 28 августа 2012

Следуя советам Гленна Джекмана и 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
1 голос
/ 04 октября 2018

Вот небольшая функция копирования для bash-переменных любого вида
- нормальные скалярные переменные
- индексированные массивы
- ассоциативные массивы

### Function vcp    -VariableCoPy-  
# $1 Name of existing Source-Variable  
# $2 Name for the Copy-Target  
vcp() {
    local var=$(declare -p $1)
    var=${var/declare /declare -g }
    eval "${var/$1=/$2=}"
}

Использование, примеры:

# declarations
var="  345  89  "
ind_array=(Betty "  345  89  ")
declare -A asso_array=([one]=Harry [two]=Betty [some_signs]=" +*.<\$~,'/ ")  

# produce the copy
vcp var varcopy
vcp ind_array ind_array_copied
vcp asso_array asso_array_2   

# now you can check the equality between original and copy with commands like
# declare -p <name>

Результаты

--3    1: "${asso_array[@]}"   
(5)       asso_array[one]:        |Harry|   
(11)      asso_array[some_signs]: | +*.<$~,'/ |   
(5)       asso_array[two]:        |Betty|   
--3    4: "${asso_array_2[@]}"   
(5)       asso_array_2[one]:        |Harry|   
(11)      asso_array_2[some_signs]: | +*.<$~,'/ |   
(5)       asso_array_2[two]:        |Betty|   
--2    7: "${ind_array[@]}"   
(5)       ind_array[0]:   |Betty|   
(11)      ind_array[1]:   |  345  89  |   
--2    9: "${ind_array_copied[@]}"   
(5)       ind_array_copied[0]:   |Betty|   
(11)      ind_array_copied[1]:   |  345  89  |   
(11)  11: "$var":   |  345  89  |  
(11)  12: "$varcopy":   |  345  89  |  
1 голос
/ 03 апреля 2018

Как насчет этого (Не создает реальную копию, просто ссылка на исходную переменную):

#!/bin/bash
declare -A my_array=(["key1"]="value1" ["key2"]="value2")
declare -n arr=my_array
arr['LOG_FILE']=/tmp/log.txt
echo ${arr['key1']}
echo ${arr['LOG_FILE']}

Напечатает:

value1
/tmp/log.txt
1 голос
/ 10 августа 2016

расширение на Luca Borrione cp_hash - что не помогло мне, и я перестал пытаться отследить проблему расширения 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
0 голосов
/ 12 июля 2011
MAINARRAY=( "${TEMPARRAY[@]}" )
...