Bash надає два типи параметрів: «скалярні» значення та масиви. Скалярне значення може бути рядком тексту (англ. string) або числом; воно позначає одну «річ».
Здебільшого скалярних значень достатньо, щоб умістити наші дані. Але іноді потрібно зберегти список скалярних значень. У такому разі нам знадобиться масив.
Масиви бувають двох видів:
Перші кілька розділів цього документа присвячено масивам із числовими індексами (далі просто «масиви»). Про асоціативні масиви йтиметься в кінці.
Масиви Bash можуть зберігати лише скалярні значення. Створити двовимірний масив (масив масивів) неможливо.
Масив можна ініціалізувати, присвоївши змінній список елементів у дужках (можливо, порожній).
myarray=("one" "two" "three")
Як і в будь-якому присвоєнні значення змінній, навколо знака рівності не повинно бути пробілів.
Між елементами немає ком-роздільників: це список рядків тексту, розділених пробільними символами.
Насправді кількість пробільних символів у дужках може бути довільною. Можна використовувати й символи нового рядка; додаймо стільки, скільки потрібно для кращої читабельності.
myarray=(
"first element"
"second element"
"this is the last element"
)
Якщо присвоїти змінній-масиву список рядків тексту в такий спосіб, перший рядок опиниться за індексом нуль, другий - за індексом один, третій - за індексом два, і так далі.
Можна ініціалізувати «розріджений масив», указавши потрібні індекси.
raindrops=([3]="Pling" [5]="Plang" [7]="Plong")
Повторимо: індекси масивів починаються з нуля. Цей фрагмент коду виводить «true»:
myarray=("one" "two" "three")
[[ "${myarray[0]}" == "one" ]] && echo true || echo false
Можна скористатися командою declare (або local усередині функції), щоб указати, що змінна міститиме масив.
declare -a myarray
Ідіоматичніше просто присвоїти змінній список у дужках (можливо, порожній), щоб її ініціалізувати.
Як ми бачили в зауваженні вище, синтаксис доступу до елемента масиву такий: ${myarray[$index]}.
Індекс задають у квадратних дужках.
Фігурні дужки обовʼязкові.
Для масивів із числовими індексами індекс є арифметичним виразом. У посібнику з 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[@]}" із символом ! перед іменем і розкриттям у подвійних лапках.
Для масивів із числовими індексами індекси розкриваються в числовому порядку.
Іноді потрібен не лише елемент, а й індекс. Є кілька способів це зробити.
Якщо відомо, що індекси утворюють неперервну послідовність, можна використати арифметичний цикл for.
for ((i = 0; i < ${#myarray[@]}; i++)); do
echo "$i -> ${myarray[i]}"
done
Звернімо увагу на синтаксис ${#myarray[@]} із символом # перед іменем масиву.
Оскільки індексація масивів починається з нуля, останній індекс масиву на одиницю менший за його довжину.
Якщо масив розріджений, можна скористатися такою формою:
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")
Памʼятаймо, що асоціативні масиви невпорядковані.
Оголошення та ініціалізацію можна записати в одному рядку.
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
Наголосимо ще раз: порядку ключів не існує.