Многомерные ассоциативные массивы в Bash - PullRequest
16 голосов
/ 27 мая 2011

Я пытаюсь создать многомерный ассоциативный массив, но мне нужна помощь.Я просмотрел страницу, предложенную в этом SO-ответе , но это смутило меня еще больше.Итак, вот что у меня есть:

Сценарий:

#!/bin/bash
declare -A PERSONS
declare -A PERSON
PERSON["FNAME"]='John'
PERSON["LNAME"]='Andrew'
PERSONS["1"]=${PERSON[@]}
PERSON["FNAME"]='Elen'
PERSON["LNAME"]='Murray'
PERSONS["2"]=${PERSON[@]}
for KEY in "${!PERSONS[@]}"; do
 TMP="${PERSONS["$KEY"]}"
 echo "$KEY - $TMP"
 echo "${TMP["FNAME"]}"
 echo "${TMP["LNAME"]}"
done

Вывод:

1 - John Andrew
John Andrew
John Andrew
2 - Elen Murray
Elen Murray
Elen Murray

Как вы можете видеть, пытаясь получить доступ к определенному индексуМассив $ TMP в цикле for возвращает весь массив.

[Q] Что мне нужно сделать, чтобы получить отдельный доступ к индексам «FNAME» и «LNAME» массива $ TMP внутри цикла for?

Спасибо.

Ответы [ 3 ]

27 голосов
/ 27 мая 2011

Вы не можете делать то, что пытаетесь сделать: массивы bash являются одномерными

$ declare -A PERSONS
$ declare -A PERSON
$ PERSON["FNAME"]='John'
$ PERSON["LNAME"]='Andrew'
$ declare -p PERSON
declare -A PERSON='([FNAME]="John" [LNAME]="Andrew" )'
$ PERSONS[1]=([FNAME]="John" [LNAME]="Andrew" )
bash: PERSONS[1]: cannot assign list to array member

Вы можете подделать многомерность, составив подходящую строку индекса массива:

declare -A PERSONS
declare -A PERSON

PERSON["FNAME"]='John'
PERSON["LNAME"]='Andrew'
i=1
for key in "${!PERSON[@]}"; do
  PERSONS[$i,$key]=${PERSON[$key]}
done

PERSON["FNAME"]='Elen'
PERSON["LNAME"]='Murray'
((i++))
for key in "${!PERSON[@]}"; do
  PERSONS[$i,$key]=${PERSON[$key]}
done

declare -p PERSONS
# ==> declare -A PERSONS='([1,LNAME]="Andrew" [2,FNAME]="Elen" [1,FNAME]="John" [2,LNAME]="Murray" )'
1 голос
/ 30 июня 2018

Я понимаю, что вам нужно. Я тоже хотел то же самое в течение нескольких недель. Я был смущен, использовать ли Python или Bash. Наконец, исследуя что-то еще, я нашел это Bash: как назначить ассоциативный массив другому имени переменной (например, переименовать переменную)?

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


#!/bin/bash

declare -A PERSONS
declare -A PERSON

PERSON["FNAME"]='John'
PERSON["LNAME"]='Andrew'
string=$(declare -p PERSON)
#printf "${string}\n"
PERSONS["1"]=${string}
#echo ${PERSONS["1"]}

PERSON["FNAME"]='Elen'
PERSON["LNAME"]='Murray'
string=$(declare -p PERSON)
#printf "${string}\n"
PERSONS["2"]=${string}
#echo ${PERSONS["2"]}

for KEY in "${!PERSONS[@]}"; do
   printf "$KEY - ${PERSONS["$KEY"]}\n"
   eval "${PERSONS["$KEY"]}"
   printf "${PERSONS["$KEY"]}\n"
   for KEY in "${!PERSON[@]}"; do
      printf "INSIDE $KEY - ${PERSON["$KEY"]}\n"
   done
done

ВЫВОД: -

1 - объявить -A ЧЕЛОВЕКА = '([FNAME] = "Джон" [LNAME] = "Андрей")'

Declare -A PERSON = '([FNAME] = "Джон" [LNAME] = "Andrew")'

ВНУТРЕННЕЕ ИМЯ - Джон

INSIDE LNAME - Эндрю

2 - объявить -A ЧЕЛОВЕКА = '([FNAME] = "Elen" [LNAME] = "Murray")'

Declare -A PERSON = '([FNAME] = "Elen" [LNAME] = "Murray")'

INSIDE FNAME - Elen

INSIDE LNAME - Мюррей


Проблема на самом деле с многомерными массивами в bash, особенно в вашем подходе, заключается в том, что вы присваиваете значения массива PERSON элементу массива PERSONS [1], который преобразуется в список, а не в ассоциированный массив при его назначении. И поэтому он больше не будет воспринимать его как 2 элемента массива, поскольку вы не сохраняете информацию о структуре данных массива в своем значении. Итак, я нашел этот взлом достаточным с одним ограничением, которое вам придется делать каждый раз, когда вы хотите сохранить / получить значения. Но это решит твою цель.

0 голосов
/ 27 мая 2011
#!/bin/bash
declare -A PERSONS
declare -A PERSON
PERSON["FNAME"]='John'
PERSON["LNAME"]='Andrew'
PERSONS["1"]=${PERSON[@]}
PERSON["FNAME"]='Elen'
PERSON["LNAME"]='Murray'
PERSONS["2"]=${PERSON[@]}
for KEY in "${!PERSONS[@]}"; do
 TMP="${PERSONS["$KEY"]}"
 echo "$KEY - $TMP"
 **echo "${PERSON["FNAME"]}"
 echo "${PERSON["LNAME"]}**"
done

Поскольку исходный массив для отдельных имен все еще активен, и на него можно ссылаться в цикле for.

...