Асоціативні масиви в сценаріях оболонок


11

Я побачив трюк для реалізації асоціативних масивів у сценарії оболонки. Наприклад, print array["apples"]може бути написано як, echo \$array$keyде key = яблука.

Однак не було згадок про те, як генерувати ключі для повторення масиву. Єдиний спосіб, про який я міг придумати, - це зберігати ключі в змінній, розмежованій пробілами, щоб я міг використовувати цикл for-циклу, щоб перебирати масив.

Отже, чи є якийсь інший спосіб зберігання ключів для подальшого використання?


5
Якщо ви намагаєтесь використовувати асоціативні масиви в сценарії оболонки, можливо, ваш проект занадто складний для сценарію оболонки :)
Мартін фон Віттіч

@MartinvonWittich чому? У мене є сценарій оболонки, який виконує сценарій SQL на одній з 3 можливих схем БД. Потрібна схема включається до назви файлів із абревіатурою. Мені потрібно зіставлення між цією абревіатурою та реальною назвою схеми. Що краще, ніж асоціативний масив, враховуючи фактичні назви схеми (а не абревіатуру), може відрізнятися між середовищами, тому змінна масиву (значення якого можна встановити лише один раз) ідеально
слов.

2
@Slav Я не сперечаюся проти асоціативних масивів, просто проти скриптів оболонок, де потрібна така складність. Але це лише мої особисті переваги; Я часто ловлю себе, починаючи писати сценарій оболонки, а потім негайно переписую його в Perl, коли розумію, що я перевищую певний поріг складності.
Мартін фон Віттіч

Відповіді:


20

Оболонки з асоціативними масивами

Деякі сучасні оболонки забезпечують асоціативні масиви: ksh93, bash ≥4, zsh. У ksh93 та bash, якщо aце асоціативний масив, то "${!a[@]}"це масив його ключів:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

У zsh цей синтаксис працює лише в режимі емуляції ksh. Інакше вам доведеться використовувати рідний синтаксис zsh:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}також працює, якщо aне має порожнього ключа.

У zsh ви також можете одночасно kпереходити до циклу на eys та values:

for k v ("${(@kv)a}") echo "$k -> $v"

Оболонки без асоціативних масивів

Емуляція асоціативних масивів у оболонках, які їх не мають, - це значно більша робота. Якщо вам потрібні асоціативні масиви, ймовірно, настав час залучити більший інструмент, наприклад ksh93 або Perl.

Якщо вам потрібні асоціативні масиви в простої оболонці POSIX, ось спосіб їх моделювання, коли ключі обмежені, щоб містити лише символи 0-9A-Z_a-z(ASCII цифри, букви та підкреслення). За цим припущенням, ключі можуть використовуватися як частина імен змінних. Наведені нижче функції діють на масив, ідентифікований префіксом імен, "стовбур", який не повинен містити двох послідовних підкреслення.

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(Попередження, неперевірений код. Виявлення помилок для синтаксично недійсних стовбурів та ключів не надається.)


5

Я не впевнений, що ви маєте на увазі під магазином, але ви можете перебирати ключі за допомогою ${!array[@]}синтаксису:

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

Отже, для повторення:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

Я знайшов хороший, короткий підручник з цього тут .


Як зазначено в коментарях нижче, асоціативні масиви були додані у bashверсії 4. Дивіться тут статтю журналу Linux на цю тему.


1
(bash version 4 only)Це важливо зазначити. Традиційно bashмасиви є лише числовими.
Рікі Бім

1
Ви можете використовувати typesetзамість declareсвоїх прикладів. Це зробило б їх портативними між bash 4 та ksh93, що вперше реалізувало асоціативні масиви оболонки.
jlliagre

0

Оболонки без асоціативних масивів

Це не так складно, коли ключі обмежені [0-9A-Za-z_](цифри, літери, підкреслення).

Трюк замість того, щоб зберігати масив [ $ key ], зберігати до змінних array_ $ key .

Набір:

eval "array_$key='$value'"

Отримайте:

value=`eval echo '$'array_$key`

Примітка. Значення не можуть містити '(одна цитата).


-1

це працює в баш

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

АБО

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

Не потрібно використовувати eval afaik


1
Я вважаю, що ви пропустили суть питання.
G-Man каже: "Відновіть Моніку"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.