Как передать ассоциативный массив в качестве аргумента функции в Bash? - PullRequest
34 голосов
/ 01 ноября 2010

Как передать ассоциативный массив в качестве аргумента функции?Возможно ли это в Bash?

Код ниже не работает должным образом:

function iterateArray
{
    local ADATA="${@}"            # associative array

for key in "${!ADATA[@]}"
do
    echo "key - ${key}"
    echo "value: ${ADATA[$key]}"

done

}

Передача ассоциативных массивов в функцию, подобную нормальным массивам, не работает:

iterateArray "$A_DATA"

или

iterateArray "$A_DATA[@]"

Ответы [ 8 ]

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

У меня была точно такая же проблема на прошлой неделе, и я долго об этом думал.

Кажется, что ассоциативные массивы нельзя сериализовать или копировать.Есть хорошая запись Bash FAQ для ассоциативных массивов, которая объясняет их подробно .Последний раздел дал мне следующую идею, которая работает для меня:

function print_array {
    # eval string into a new associative array
    eval "declare -A func_assoc_array="${1#*=}
    # proof that array was successfully created
    declare -p func_assoc_array
}

# declare an associative array
declare -A assoc_array=(["key1"]="value1" ["key2"]="value2")
# show associative array definition
declare -p assoc_array

# pass associative array in string form to function
print_array "$(declare -p assoc_array)" 
10 голосов
/ 12 сентября 2015

На основании Решение Флориана Фельдхауса:

# Bash 4+ only
function printAssocArray # ( assocArrayName ) 
{
    var=$(declare -p "$1")
    eval "declare -A _arr="${var#*=}
    for k in "${!_arr[@]}"; do
        echo "$k: ${_arr[$k]}"
    done

}

declare -A conf
conf[pou]=789
conf[mail]="ab\npo"
conf[doo]=456

printAssocArray "conf" 

Вывод будет:

doo: 456
pou: 789
mail: ab\npo
6 голосов
/ 10 июня 2012

Обновление, чтобы полностью ответить на вопрос, вот небольшой раздел из моей библиотеки:

Итерация ассоциативного массива по ссылке

shopt -s expand_aliases
alias array.getbyref='e="$( declare -p ${1} )"; eval "declare -A E=${e#*=}"'
alias array.foreach='array.keys ${1}; for key in "${KEYS[@]}"'

function array.print {
    array.getbyref
    array.foreach
    do
        echo "$key: ${E[$key]}"
    done
}

function array.keys {
    array.getbyref
    KEYS=(${!E[@]})
}   

# Example usage:
declare -A A=([one]=1 [two]=2 [three]=3)
array.print A

Это мы разработали мою предыдущую работу, которую я оставлю ниже.

@ ffeldhaus - хороший ответ, я взял его и побежал с ним:

t() 
{
    e="$( declare -p $1 )"
    eval "declare -A E=${e#*=}"
    declare -p E
}

declare -A A='([a]="1" [b]="2" [c]="3" )'
echo -n original declaration:; declare -p A
echo -n running function tst: 
t A

# Output:
# original declaration:declare -A A='([a]="1" [b]="2" [c]="3" )'
# running function tst:declare -A E='([a]="1" [b]="2" [c]="3" )'
4 голосов
/ 11 января 2011

Вы можете передавать ассоциативные массивы только по имени.

Лучше (эффективнее) также передавать обычные массивы по имени.

3 голосов
/ 07 сентября 2017

года:

 #!/bin/bash
   declare -A dict

   dict=(
    [ke]="va"
    [ys]="lu"
    [ye]="es" 
   )

   fun() {
     for i in $@; do
       echo $i
     done
    }

   fun ${dict[@]} # || ${dict[key]} || ${!dict[@] || ${dict[$1]} 

Ez

1 голос
/ 14 марта 2019

Если вы используете Bash 4.3 или новее, clean способ состоит в том, чтобы передать ассоциативный массив по имени и затем получить доступ к нему внутри вашей функции, используя ссылку на имя с local -n.Например:

function foo {
    local -n data_ref=$1
    echo ${data_ref[a]} ${data_ref[b]}
}

declare -A data
data[a]="Fred Flintstone"
data[b]="Barney Rubble"
foo data

Вам не нужно использовать суффикс _ref;это только то, что я выбрал здесь.Вы можете вызывать ссылку как угодно, если она отличается от исходного имени переменной (в противном случае вы получите ошибку «циклическая ссылка на имя»).

1 голос
/ 24 июня 2016

Вот решение, которое я предложил сегодня, используя eval echo ... для выполнения перенаправления:

print_assoc_array() {
    local arr_keys="\${!$1[@]}" # \$ means we only substitute the $1
    local arr_val="\${$1[\"\$k\"]}"
    for k in $(eval echo $arr_keys); do #use eval echo to do the next substitution
        printf "%s: %s\n" "$k" "$(eval echo $arr_val)"
    done
}

declare -A my_arr
my_arr[abc]="123"
my_arr[def]="456"
print_assoc_array my_arr

Выходы на bash 4.3:

def: 456
abc: 123
0 голосов
/ 05 сентября 2011

Из лучших Руководство Bash когда-либо:

declare -A fullNames
fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
for user in "${!fullNames[@]}"
do
    echo "User: $user, full name: ${fullNames[$user]}."
done

Я думаю, что проблема в вашем случае заключается в том, что $@ это , а не ассоциативный массив : "@: расширяется до всех слов всех позиционных параметров. Если двойные кавычки , он расширяется до списка всех позиционных параметров как отдельных слов. "

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