Ма

Масиви у Bash

{one: "1 вправа", few: "%{count} вправи", many: "%{count} вправ", other: "%{count} вправи"}

Про концепцію Масиви

Bash надає два типи параметрів: «скалярні» значення та масиви. Скалярне значення може бути рядком тексту (англ. string) або числом; воно позначає одну «річ».

Здебільшого скалярних значень достатньо, щоб умістити наші дані. Але іноді потрібно зберегти список скалярних значень. У такому разі нам знадобиться масив.

Масиви бувають двох видів:

  • Масиви з числовими індексами зіставляють цілочисловий ключ зі значенням, яке є рядком тексту. (В інших мовах це можуть називати «списком» або «послідовністю».)
  • Асоціативні масиви зіставляють ключ, який є рядком тексту, зі значенням, яке теж є рядком тексту. (В інших мовах це можуть називати «мапою» або «словником».)

Перші кілька розділів цього документа присвячено масивам із числовими індексами (далі просто «масиви»). Про асоціативні масиви йтиметься в кінці.

Caution

Масиви Bash можуть зберігати лише скалярні значення. Створити двовимірний масив (масив масивів) неможливо.

Оголошення й ініціалізація змінної-масиву

Масив можна ініціалізувати, присвоївши змінній список елементів у дужках (можливо, порожній).

myarray=("one" "two" "three")

Як і в будь-якому присвоєнні значення змінній, навколо знака рівності не повинно бути пробілів.

Між елементами немає ком-роздільників: це список рядків тексту, розділених пробільними символами.

Насправді кількість пробільних символів у дужках може бути довільною. Можна використовувати й символи нового рядка; додаймо стільки, скільки потрібно для кращої читабельності.

myarray=(
    "first element"
    "second element"
    "this is the last element"
)

Якщо присвоїти змінній-масиву список рядків тексту в такий спосіб, перший рядок опиниться за індексом нуль, другий - за індексом один, третій - за індексом два, і так далі.

Можна ініціалізувати «розріджений масив», указавши потрібні індекси.

raindrops=([3]="Pling" [5]="Plang" [7]="Plong")
Note

Повторимо: індекси масивів починаються з нуля. Цей фрагмент коду виводить «true»:

myarray=("one" "two" "three")
[[ "${myarray[0]}" == "one" ]] && echo true || echo false

Можна скористатися командою declare (або local усередині функції), щоб указати, що змінна міститиме масив.

declare -a myarray

Ідіоматичніше просто присвоїти змінній список у дужках (можливо, порожній), щоб її ініціалізувати.

Доступ до елементів масиву

Як ми бачили в зауваженні вище, синтаксис доступу до елемента масиву такий: ${myarray[$index]}. Індекс задають у квадратних дужках. Фігурні дужки обовʼязкові.

Note

Для масивів із числовими індексами індекс є арифметичним виразом. У посібнику з Bash сказано:

В арифметичному виразі на змінні оболонки можна також посилатися за іменем, не використовуючи синтаксис розкриття параметрів.

Це означає, що для «простого» розкриття змінної $ не потрібен. Елементи можна читати так, і це трохи легше сприймати:

i=5
echo "${myarray[i]}"
# ..............^

Якщо заданого індексу немає в масиві, результатом розкриття буде порожній рядок тексту.

Присвоєння елементів масиву

Щоб присвоїти значення конкретному елементу масиву, використовують такий синтаксис:

myarray[10]="hello"

Щоб дописати елементи в кінець масиву, використовують оператор конкатенації з присвоєнням += і дужки:

myarray+=("new element 1" "new element 2")

Перебирання масиву

Зазвичай нам потрібно перебрати значення масиву. Для цього використовують цикл for (той самий, що ми бачили в концепції Цикли):

myarray=("one" "two" "three")
for value in "${myarray[@]}"; do
    echo "$value"
done

Звернімо увагу на спеціальний синтаксис розкриття масиву: "${myarray[@]}" Ця форма розкриття параметрів підставляє значення масиву як окремі слова. Це приблизно еквівалентно такому:

for value in "${myarray[0]}" "${myarray[1]}" ... "${myarray[n]}"

Форма "${myarray[@]}" працює й з розрідженими масивами: вона розкривається лише в задані значення.

Це спеціальне розкриття, у якому індексом є символ @, особливе лише всередині подвійних лапок.

Інші спеціальні розкриття параметрів

Ось ще кілька елементів спеціального синтаксису, потрібних для перебирання масиву. Вони описані в посібнику в розділі Розкриття параметрів оболонки.

Щоб дізнатися довжину масиву, використовують ${#myarray[@]} із символом # перед іменем. «Довжина» масиву означає кількість елементів у ньому.

Щоб отримати список індексів масиву, використовують "${!myarray[@]}" із символом ! перед іменем і розкриттям у подвійних лапках. Для масивів із числовими індексами індекси розкриваються в числовому порядку.

Перебирання індексів масиву

Іноді потрібен не лише елемент, а й індекс. Є кілька способів це зробити.

  1. Якщо відомо, що індекси утворюють неперервну послідовність, можна використати арифметичний цикл for.

    for ((i = 0; i < ${#myarray[@]}; i++)); do
        echo "$i -> ${myarray[i]}"
    done
    

    Звернімо увагу на синтаксис ${#myarray[@]} із символом # перед іменем масиву. Оскільки індексація масивів починається з нуля, останній індекс масиву на одиницю менший за його довжину.

  2. Якщо масив розріджений, можна скористатися такою формою:

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

    Звернімо увагу на синтаксис ${!myarray[@]} із символом ! перед іменем масиву.

Перегляд вмісту масиву

Щоб подивитися вміст масиву, використовують команду declare з опцією -p:

a=("the 'first' element"
   second
   third
   'the "last" element')
declare -p a

Це виводить вміст із канонічним для оболонки лапкуванням.

declare -a a=([0]="the 'first' element" [1]="second" [2]="third" [3]="the \"last\" element")

Асоціативні масиви

Повторимо: в асоціативних масивах як індекси використовують рядки тексту, а не числа. Усе написане вище стосується й асоціативних масивів, але з невеликими відмінностями. Зазвичай ми вживаємо термін «ключ», а не «індекс»: асоціативні масиви зіставляють ключі зі значеннями.

Оголошення асоціативного масиву

На відміну від звичайних масивів, асоціативні масиви обовʼязково потрібно оголошувати. Для цього використовують опцію -A команди declare (або local у функції):

declare -A mymap

myfunc() {
    local -A my_local_map
    # ...
}

Ініціалізація асоціативного масиву

Пари ключ-значення задають у списку в дужках:

mymap=([first]=foo [second]=bar [third]=baz)
declare -p mymap

Це виводить:

declare -A mymap=([second]="bar" [first]="foo" [third]="baz")
Note

Памʼятаймо, що асоціативні масиви невпорядковані.

Оголошення та ініціалізацію можна записати в одному рядку.

declare -A mymap=([first]=foo [second]=bar [third]=baz)

У новіших версіях Bash для ініціалізації можна використати список (key value key value ...).

declare -A mymap=(first foo second bar third baz)

Доступ до значень

Для доступу до елементів використовують той самий синтаксис, що й раніше: ${mymap[$key]}.

Ключі асоціативних масивів не обчислюються в арифметичному контексті. Тут потрібен звичайний синтаксис розкриття параметрів.

Присвоєння в асоціативному масиві

Присвоєння використовує той самий синтаксис, що й раніше:

mymap[$key]="$value"

Перебирання

Для перебирання можна використати цикл for value in "${mymap[@]}". Однак зазвичай потрібен і ключ разом зі значенням.

Використаймо синтаксис "${!mymap[@]}", який ми бачили вище.

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

Це виводить

second -> bar
first -> foo
third -> baz

Наголосимо ще раз: порядку ключів не існує.

Редагувати через GitHub Посилання відкривається в новому вікні або вкладці