2. Massivlar va lug'atlar โ
๐ฏ Bu bobda nimani o'rganasiz:
- Indexed array โ
arr=(a b c), qo'shish, o'chirish, iteratsiya- Associative array (lug'at) โ
declare -A(Bash 4+)"${arr[@]}"vs"${arr[*]}"โ kritik farqIFSorqali CSV va string parsing- Real misol โ kichik TODO list manager
โฑ Vaqt: ~30 daqiqa ๐งช Mashqlar:
bashlings watch 07_arrays(kelajak sprint)
2.1. Nima uchun massivlar? โ
Tasavvur qiling โ skriptingiz uchta serverga deploy qiladi. Birinchi yondashuv:
servers="alpha beta gamma"
for s in $servers; do
deploy "$s"
doneIshlaydi. Lekin agar server nomida probel bo'lsa-chi? "beta server"? Bash uni 2 ta alohida elementga ajratib yuboradi:
servers="alpha beta server gamma"
# deploy: alpha, beta, server, gamma โ 4 ta!Massiv esa rasmiy ma'lumot tuzilmasi โ har element o'z hujayrasida saqlanadi:
servers=("alpha" "beta server" "gamma")
for s in "${servers[@]}"; do
deploy "$s"
done
# deploy: alpha, "beta server", gamma โ 3 ta, to'g'ri โAsosiy g'oya
Bash'da har qachon bir nechta qiymatni saqlash kerak bo'lsa โ string emas, massiv ishlating. Probel, maxsus belgilar va word-splitting tuzog'idan saqlaydi.
2.2. Indexed array โ e'lon qilish โ
Indexed array โ eng oddiy turi: elementlar butun son indekslar bilan saqlanadi (0'dan boshlab).
Sintaksis variantlari โ
# Bo'sh massiv
arr=()
# Bir nechta element bilan
fruits=("olma" "anor" "uzum")
# Diapazon (brace expansion)
nums=({1..10}) # 1 2 3 4 5 6 7 8 9 10
# Aralash tipdagi qiymatlar bilan
mixed=("matn" 42 3.14 "yana matn")declare -a bilan aniqlash โ
declare -a cities
cities[0]="Toshkent"
cities[1]="Samarqand"
cities[2]="Buxoro"declare -a โ bash'da indexed array ekanligini aniq belgilaydi. Funksiya ichida local -a shaklida ishlatiladi.
Indekslar 0'dan boshlanadi โ
fruits=("olma" "anor" "uzum")
# โ0 โ1 โ2Buyruq natijasidan ehtiyot bo'ling
files=($(ls *.txt)) # โ XAVFLISababi: agar fayl nomida probel bo'lsa, ls chiqishini bash o'zi word-splitting qiladi. my file.txt โ "my" va "file.txt" โ ikki element bo'lib qoladi.
To'g'ri yo'l (Bash 4+):
mapfile -t files < <(ls *.txt)2.3. Elementlar bilan ishlash โ
Yagona elementga kirish โ
fruits=("olma" "anor" "uzum")
echo "${fruits[0]}" # olma
echo "${fruits[1]}" # anor
echo "${fruits[-1]}" # uzum (oxirgi โ Bash 4.2+)โ Diqqat: $fruits (${fruits}'siz, indekssiz) birinchi elementni qaytaradi, hammasini emas. Bu klassik tuzoq.
echo "$fruits" # olma โ ko'pchilik buni "hammasi" deb o'ylaydi
echo "${fruits[@]}" # olma anor uzum โMassiv uzunligi (element soni) โ
echo "${#fruits[@]}" # 3Element qo'shish (append) โ
fruits+=("shaftoli") # oxiriga qo'shadi
echo "${fruits[@]}" # olma anor uzum shaftoliBir nechta elementni birga qo'shish:
fruits+=("nok" "olcha")Element o'zgartirish โ
fruits[1]="banan"
echo "${fruits[@]}" # olma banan uzum shaftoli ...Element o'chirish โ
unset 'fruits[1]'
echo "${fruits[@]}" # olma uzum shaftoli ...unset "tirik holat" qoldiradi
unset arr[1] โ elementni o'chiradi, lekin indekslarni qayta tartiblamaydi:
arr=(a b c d)
unset 'arr[1]'
echo "${arr[@]}" # a c d (b ketdi)
echo "${arr[2]}" # c (indeks 2 saqlanib qoldi)
echo "${arr[1]}" # (bo'sh โ chunki o'chirilgan)Indekslarni jamlash uchun qayta yozish kerak:
arr=("${arr[@]}")Butun massivni o'chirish โ
unset fruits # massiv butunlay yo'qoladi2.4. Iteratsiya โ
Eng keng tarqalgan โ for ... in โ
fruits=("olma" "anor" "uzum")
for f in "${fruits[@]}"; do
echo "Meva: $f"
doneTirnoqlarni unutmang!
for f in ${fruits[@]} โ tirnoqsiz โ har elementni word-split qiladi. Har doim "${fruits[@]}" shaklida yozing.
Indekslar bilan โ
Element + uning pozitsiyasi kerak bo'lsa:
fruits=("olma" "anor" "uzum")
for i in "${!fruits[@]}"; do
echo "$i: ${fruits[$i]}"
done
# 0: olma
# 1: anor
# 2: uzum${!arr[@]} โ indekslar ro'yxatini qaytaradi (qiymatlar emas).
Slicing โ qismli kesish โ
nums=(10 20 30 40 50 60 70)
# ${arr[@]:start:count}
echo "${nums[@]:2:3}" # 30 40 50 (2-pozitsiyadan boshlab 3 ta)
echo "${nums[@]:4}" # 50 60 70 (4-pozitsiyadan oxirigacha)
echo "${nums[@]: -2}" # 60 70 (oxirgi 2 ta โ probel kerak!)Negativ slicing
${nums[@]:-2} โ bu default qiymat operatori, slicing emas! Negativ offset uchun probel kerak: ${nums[@]: -2}.
while orqali (kamroq uchraydi) โ
i=0
while [[ $i -lt ${#fruits[@]} ]]; do
echo "${fruits[$i]}"
((i++))
done2.5. "${arr[@]}" vs "${arr[*]}" โ kritik farq โ
Bu bashning eng ko'p chalkashadigan jihati. Ikkalasi ham "hamma element" deb tushuniladi, lekin tirnoq ichida butunlay boshqacha ishlaydi.
arr=("salom dunyo" "bash" "uz")
# @ โ har element alohida
for x in "${arr[@]}"; do echo "[$x]"; done
# [salom dunyo]
# [bash]
# [uz]
# * โ bitta string, IFS belgisi bilan ulangan (default IFS = probel)
for x in "${arr[*]}"; do echo "[$x]"; done
# [salom dunyo bash uz] โ bitta string!| Sintaksis | Tirnoq ichida natija |
|---|---|
"${arr[@]}" | Har element โ alohida argument |
"${arr[*]}" | Bitta string, IFS bilan birlashtirilgan |
${arr[@]} | Tirnoqsiz โ word-splitting xavfi |
Qoida
99% holatlarda "${arr[@]}" ishlatiladi. "${arr[*]}" faqat stringga aylantirish kerak bo'lganda.
IFS bilan custom separator โ
${arr[*]} IFS belgisini ishlatadi:
arr=("a" "b" "c")
IFS=, echo "${arr[*]}"
# a,b,c
IFS='|' echo "${arr[*]}"
# a|b|cAslida bu โ ro'yxatni CSV satrga aylantirish texnikasi.
2.6. Associative arrays โ lug'atlar (Bash 4+) โ
Associative array โ string kalitlar bilan saqlash. Boshqa tillarda buni "dictionary", "map" yoki "hashtable" deyiladi.
macOS muammosi
macOS'da default bash โ 3.2 (2007-yildan). U associative array'ni qo'llab-quvvatlamaydi.
Hal qilish:
brew install bash
which bash # /opt/homebrew/bin/bashSkript boshida #!/usr/bin/env bash โ env PATH'dan yangiroq bash ni topadi.
Versiyani tekshirish:
bash --version # 5.x bo'lishi kerakE'lon qilish va to'ldirish โ
declare -A user
user[name]="Ali"
user[age]=25
user[city]="Toshkent"Yoki bir martda:
declare -A user=(
[name]="Ali"
[age]=25
[city]="Toshkent"
)Qiymatlarga kirish โ
echo "${user[name]}" # Ali
echo "${user[age]}" # 25Mavjud bo'lmagan kalit โ bo'sh string qaytaradi (xato emas):
echo "${user[phone]}" # (bo'sh)Kalitlar va qiymatlar โ
echo "${!user[@]}" # name age city (kalitlar)
echo "${user[@]}" # Ali 25 Toshkent (qiymatlar)
echo "${#user[@]}" # 3 (jami)Tartib kafolatlanmaydi
Associative array'da kalitlar tartibi hash table ichki tuzilmasiga bog'liq. Iteratsiya tartibi ishonchli emas. Tartibli kerak bo'lsa, alohida indexed array'da kalitlarni saqlang.
Iteratsiya โ
for key in "${!user[@]}"; do
echo "$key = ${user[$key]}"
done
# name = Ali
# age = 25
# city = ToshkentElement o'chirish โ
unset 'user[city]'Real misol โ fayllar to'plami uchun counter โ
#!/usr/bin/env bash
declare -A count
# Joriy katalogdagi fayllar ekstensiyasini sanash
for f in *; do
ext="${f##*.}"
((count[$ext]++))
done
for ext in "${!count[@]}"; do
printf '%-10s %d\n' "$ext" "${count[$ext]}"
doneNatija:
md 12
sh 8
txt 32.7. IFS va string parsing โ
IFS (Internal Field Separator) โ bash'ning word-splitting belgisi. Default qiymati: probel + tab + newline.
read -ra โ stringni massivga ajratish โ
csv="ali,25,toshkent"
IFS=',' read -ra fields <<< "$csv"
echo "${fields[0]}" # ali
echo "${fields[1]}" # 25
echo "${fields[2]}" # toshkent-r โ backslash'larni o'zgartirmaslik (har doim ishlatish kerak). -a fields โ natijani fields massiviga yozish. <<< โ here-string (bir qatorli stdin).
Massivni stringga birlashtirish โ
words=("salom" "dunyo" "bash")
# Probel bilan
result="${words[*]}"
echo "$result" # salom dunyo bash
# Custom separator bilan
(IFS=','; result="${words[*]}"; echo "$result")
# salom,dunyo,bashSubshell bilan IFS ehtiyot
(IFS=','; ...) ni qavslarga olganimiz IFS ni o'zgartirish faqat shu blokda qolishi uchun. Tashqarida IFS o'zgarmaydi.
Fayldan satrlarni massivga โ
# Bash 4+ uchun eng ravon yo'l
mapfile -t lines < /etc/passwd
echo "${#lines[@]}" # qator soni
echo "${lines[0]}" # birinchi qatormapfile -t โ har qatorni alohida element qiladi, -t newline'ni olib tashlaydi.
Eski bash uchun:
lines=()
while IFS= read -r line; do
lines+=("$line")
done < /etc/passwd2.8. Real misol โ TODO list manager โ
Massivlarni amalda ko'rsatuvchi to'liq misol:
#!/usr/bin/env bash
#
# todo.sh โ kichik TODO list manager
#
# Foydalanish:
# todo.sh add "Buyruq"
# todo.sh list
# todo.sh done 2
#
set -euo pipefail
readonly TODO_FILE="${TODO_FILE:-$HOME/.todo}"
# Faylni yuklash (massiv sifatida)
load_tasks() {
if [[ -f "$TODO_FILE" ]]; then
mapfile -t tasks < "$TODO_FILE"
else
tasks=()
fi
}
# Massivni faylga saqlash
save_tasks() {
printf '%s\n' "${tasks[@]}" > "$TODO_FILE"
}
cmd_add() {
local item="$*"
[[ -z "$item" ]] && { echo "Foydalanish: todo add <matn>" >&2; exit 1; }
tasks+=("$item")
save_tasks
echo "โ Qo'shildi: $item"
}
cmd_list() {
if [[ ${#tasks[@]} -eq 0 ]]; then
echo "(ro'yxat bo'sh)"
return
fi
for i in "${!tasks[@]}"; do
printf '%2d. %s\n' "$((i + 1))" "${tasks[$i]}"
done
}
cmd_done() {
local n="$1"
local idx=$((n - 1))
if [[ -z "${tasks[$idx]:-}" ]]; then
echo "โ #$n topilmadi" >&2
exit 1
fi
echo "โ Bajarildi: ${tasks[$idx]}"
unset 'tasks[idx]'
tasks=("${tasks[@]}") # qayta indekslab jamlash
save_tasks
}
# --- Asosiy ---
load_tasks
case "${1:-list}" in
add) shift; cmd_add "$@" ;;
list) cmd_list ;;
done) cmd_done "$2" ;;
*) echo "Foydalanish: $0 {add|list|done}"; exit 1 ;;
esacSinab ko'ramiz:
$ todo.sh add "non sotib olish"
โ Qo'shildi: non sotib olish
$ todo.sh add "kitobni o'qish"
โ Qo'shildi: kitobni o'qish
$ todo.sh list
1. non sotib olish
2. kitobni o'qish
$ todo.sh done 1
โ Bajarildi: non sotib olish
$ todo.sh list
1. kitobni o'qishBu misolda nima ishlatildi? โ
| Texnika | Qaerda |
|---|---|
mapfile -t (fayl โ massiv) | load_tasks |
printf '%s\n' "${arr[@]}" | save_tasks (faylga yozish) |
tasks+=(...) qo'shish | cmd_add |
"${!arr[@]}" indekslar | cmd_list |
unset 'arr[i]' + qayta jamlash | cmd_done |
${var:-default} bo'sh qiymat tekshirish | cmd_list |
2.9. Tez-tez uchraydigan xatolar โ
Klassik tuzoqlar
$arrโ faqat birinchi element.basharr=(a b c) echo "$arr" # a โ echo "${arr[@]}" # a b c โTirnoqsiz iteratsiya.
bashfor x in ${arr[@]}; do ... # โ word-splitting for x in "${arr[@]}"; do ... # โ$(ls)ni massivga to'ldirish.bashfiles=($(ls)) # โ probelli fayl nomlari sinadi mapfile -t files < <(ls) # โunsetindekslarni qaytarib bermaydi.unset 'arr[1]'keyin${#arr[@]}2 emas, hali ham${arr[2]}mavjud. Yechim:arr=("${arr[@]}")bilan jamlash.macOS'da associative array ishlamaydi. Default bash 3.2 โ
declare -Axato beradi.brew install bashkerak.Negativ slicing va default qiymat aralashishi.
bash"${arr[@]:-2}" # โ default qiymat "${arr[@]: -2}" # โ oxirgi 2 element (probel!)Quote'siz string birlashtirish.
bashIFS=',' echo "${arr[*]}" # โ echo IFS'ni ko'rmaydi (IFS=','; echo "${arr[*]}") # โ subshell ichida
2.10. Mashqlar โ
๐งช Kelajakda quyidagilar
bashlings watch 07_arraysorqali avto-tekshiriladi.
reverse_arrayโ funksiya yozing, massivni teskari tartibda chiqarsin. Hint:for ((i=${#arr[@]}-1; i>=0; i--))unique_itemsโ massivdan takrorlarsiz elementlarni qaytarsin. Hint:sort -ubilan birlashtirish.csv_to_dictโ"key1=val1,key2=val2,..."formatli stringni associative array'ga aylantiruvchi funksiya.top_nโ sonli massiv vanargument oladi, eng kattanta sonni qaytaradi.sort -rn | headpatterni.group_by_extโ joriy katalogdagi fayllarni ekstensiyasi bo'yicha guruhlasin (associative array). Misol natija:md: [README.md doc.md] sh: [build.sh test.sh]
2.11. Xulosa โ
| Tushuncha | Asosiy nuqta |
|---|---|
| Indexed array | arr=(a b c) yoki declare -a |
| Associative array | declare -A (Bash 4+ majburiy) |
| Hammasi | "${arr[@]}" (har element alohida) |
| Bitta string | "${arr[*]}" (IFS bilan birlashtirilgan) |
| Element soni | ${#arr[@]} |
| Kalitlar/indekslar | "${!arr[@]}" |
| Qo'shish | arr+=("yangi") |
| Slicing | "${arr[@]:start:count}" |
| Fayl โ massiv | mapfile -t arr < fayl.txt |
| Stringni split | IFS=',' read -ra arr <<< "$s" |
| Macros tirnoq | Har doim "${arr[@]}" โ tirnoqsiz xavfli |
Asosiy g'oyalar โ
- Massiv = bir nechta qiymat saqlash. String โ yagona qiymat.
@har doim ishlating โ*faqat string birlashtirish uchun.- macOS bash 3.2 โ associative array ishlamaydi, brew bash kerak.
mapfileโ fayldan massivga eng xavfsiz yo'l.unsetqoldiq qoldiradi โarr=("${arr[@]}")bilan jamlang.
๐ Endi sizda Bash'da kuchli ma'lumot strukturalari ishlatish ko'nikmasi bor. Keyingi bobda biz sed va awk orqali matnlarni industrial darajada qayta ishlashni o'rganamiz.
Keyingi sahifa: 3. sed, awk va grep mahorat โ