Как передать ассоциативный массив в качестве аргумента функции в Bash?
Как передать ассоциативный массив в качестве аргумента функции? Возможно ли это в 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[@]"
Ответы
Ответ 1
У меня была точно такая же проблема на прошлой неделе, и я подумал об этом довольно долго.
Кажется, что ассоциативные массивы не могут быть сериализованы или скопированы. Там есть хорошая запись 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)"
Ответ 2
Основано на
Решение Флориана Фельдхауса:
# 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
Ответ 3
Обновление, чтобы полностью ответить на вопрос, вот небольшой раздел из моей библиотеки:
Итерация ассоциативного массива с помощью ссылки
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
Вы можете передавать ассоциативные массивы только по имени.
Лучше (более эффективно) передавать регулярные массивы по имени.
Ответ 5
Если вы используете Bash 4.3 или новее, самый простой способ - передать ассоциативный массив по имени, а затем получить к нему доступ внутри своей функции, используя ссылку на имя с 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
; это именно то, что я выбрал здесь. Вы можете вызывать ссылку как угодно, если она отличается от исходного имени переменной (в противном случае вы получите ошибку "циклическая ссылка на имя").
Ответ 6
лет:
#!/bin/bash
declare -A dict
dict=(
[ke]="va"
[ys]="lu"
[ye]="es"
)
fun() {
for i in [email protected]; do
echo $i
done
}
fun ${dict[@]} # || ${dict[key]} || ${!dict[@] || ${dict[$1]}
Ez
Ответ 7
Из лучшего Bash guide ever:
declare -A fullNames
fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
for user in "${!fullNames[@]}"
do
echo "User: $user, full name: ${fullNames[$user]}."
done
Я думаю, что в вашем случае проблема заключается в том, что [email protected]
не является ассоциативным массивом: "@: расширяется до всех слов всех позиционные параметры. Если двойной кавычек, он расширяется до списка всех позиционных параметров как отдельных слов."
Ответ 8
Вот решение, которое я придумал сегодня, используя 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