---
title: 'Diziler ve İlişkisel Diziler'
source: 'https://academia.sh/tr/kurslar/kabuk-programlama/diziler-ve-iliskisel-diziler'
course: 'Kabuk Programlama'
language: tr
updated: '2026-08-17T18:10:01+00:00'
license: 'CC BY-SA 4.0'
---

# Diziler ve İlişkisel Diziler

Dizinli ve ilişkisel dizilerin tanımı, toplu genişletme, seyreklik, tek geçişte sayım ve sürüm bağımlılığının denetlenmesi.

Rapordaki her sayım kütüğü baştan sona bir kez daha okuyor: beş sayım için beş tarama.
Küçük dosyalarda bu fark edilmez, kütük büyüdükçe belirginleşir. Tek taramaya inmek, ara
sonuçları bellekte tutmayı gerektirir.

Veri Yapıları kursunda bu iş için iki yapı tanımlanmıştı: dizinle erişilen **dizi** ve
anahtarla erişilen **karma tablosu**. Kabuk her ikisinin de bir biçimini sunar. Bu ders
onları, sözdizim tuzaklarını ve — ilişkisel diziler için kaçınılmaz olan — sürüm
bağımlılığını ele alır.

## Dizinli Diziler

Dizi, parantez içinde kelime listesiyle tanımlanır. Dizinler sıfırdan başlar.

```sh
siniflar=(2 3 4 5)
echo "ilk=${siniflar[0]} son=${siniflar[3]} sayi=${#siniflar[@]}"
```

```
ilk=2 son=5 sayi=4
```

Süslü ayraçlar zorunludur: `$siniflar[0]` yazımı, `siniflar` değişkeninin değerinin
ardına `[0]` metnini ekler. Ayraçsız yazımda `$siniflar` tek başına **ilk elemanı** verir
— tüm diziyi değil.

## Toplu Genişletme

Diziyi bütün olarak genişletmenin iki biçimi vardır ve fark, argüman listelerindeki
`"$@"`–`"$*"` ayrımıyla aynıdır.

```sh
say() { printf 'sayi=%d\n' "$#"; printf '  <%s>\n' "$@"; }
yollar=("/api/veri" "/urun/12" "iki kelimeli yol")
say "${yollar[@]}"
say "${yollar[*]}"
say ${yollar[@]}
```

```
sayi=3
  </api/veri>
  </urun/12>
  <iki kelimeli yol>
sayi=1
  </api/veri /urun/12 iki kelimeli yol>
sayi=5
  </api/veri>
  </urun/12>
  <iki>
  <kelimeli>
  <yol>
```

Kural değişmedi: **`"${dizi[@]}"` yazılır.** Tırnaksız biçim elemanları böler, `[*]`
biçimi hepsini tek metne indirger.

Diziler fonksiyonlara doğrudan geçirilemez; kabukta fonksiyon argümanları yalnızca
kelime listesidir. Aktarım genişletmeyle yapılır:

```sh
yaz() { printf 'aldigim: %s\n' "$@"; }
yaz "${yollar[@]}"
```

```
aldigim: /api/veri
aldigim: /urun/12
aldigim: iki kelimeli yol
```

Bu, dizinin kopyalanarak geçtiği anlamına gelir; fonksiyon içindeki değişiklikler çağırana
dönmez.

## Ekleme, Dizinler ve Seyreklik

`+=` işleci diziye sona ekler. `${!dizi[@]}` kullanılan dizinleri verir.

```sh
yollar+=("/panel")
echo "sayi=${#yollar[@]} dizinler=${!yollar[@]}"
```

```
sayi=4 dizinler=0 1 2 3
```

Kabuk dizileri **seyrek (sparse)** olabilir: bir eleman silindiğinde kalanlar kaymaz ve
dizinlerde boşluk oluşur.

```sh
unset 'yollar[1]'
echo "sayi=${#yollar[@]} dizinler=${!yollar[@]}"
echo "son eleman=${yollar[-1]}"
```

```
sayi=3 dizinler=0 2 3
son eleman=/panel
```

Bu, dizi üzerinde `for ((i = 0; i < ${#dizi[@]}; i++))` biçiminde dönmenin neden yanlış
olduğunu gösterir: eleman sayısı 3, ama geçerli dizinler 0, 2 ve 3'tür. Doğru yazımlar
`for e in "${dizi[@]}"` ya da `for i in "${!dizi[@]}"` biçimindedir.

`unset 'yollar[1]'` yazımındaki tırnak gereklidir; tırnaksız bırakılırsa `[1]` bir yol adı
kalıbı olarak yorumlanabilir.

Dilimleme, `${dizi[@]:baslangic:adet}` biçimiyle yapılır:

```sh
tam=(a b c d e)
echo "1..3: ${tam[@]:1:3}"
```

```
1..3: b c d
```

## Komut Çıktısından Dizi Kurmak

`mapfile` (eşanlamlısı `readarray`) bir akışı satır satır diziye okur. `-t` seçeneği satır
sonlarını atar.

```sh
mapfile -t kodlar < <(cut -d' ' -f9 erisim.log | sort -u)
echo "farkli kod sayisi=${#kodlar[@]} -> ${kodlar[*]}"
```

```
farkli kod sayisi=8 -> 200 201 301 302 304 403 404 500
```

`dizi=( $(komut) )` biçiminde yazmak yaygın ama yanlıştır: çıktı kelime bölmeye ve yol
adı genişletmesine uğrar, boşluk içeren satırlar parçalanır. `mapfile` bu iki işlemi
uygulamaz. Bash 4.0 ve sonrasında bulunur.

## İlişkisel Diziler

`declare -A` bildirimi, anahtarı dizgi olan bir dizi yaratır. Bu, kabuğun karma tablosu
karşılığıdır ve tek geçişte sayım yapmayı mümkün kılar.

```sh
declare -A sayim
while read -r kod; do
  sayim["$kod"]=$(( ${sayim["$kod"]:-0} + 1 ))
done < <(cut -d' ' -f9 erisim.log)

for k in "${!sayim[@]}"; do printf '%s -> %s\n' "$k" "${sayim[$k]}"; done | sort
```

```
200 -> 17
201 -> 1
301 -> 1
302 -> 1
304 -> 1
403 -> 2
404 -> 4
500 -> 3
```

`${sayim["$kod"]:-0}` gösterimi, ilk kez görülen anahtarın sıfırdan başlamasını sağlar;
öntanımlı değer gösterimlerinin dizi elemanlarında da çalıştığını gösterir.

Anahtarların sırası tanımsızdır — karma tablosunun doğal sonucudur. Sıralı çıktı
isteniyorsa `sort` gerekir; yukarıdaki örnekte bu yüzden vardır.

Bir anahtarın varlığı `-v` testiyle sınanır:

```sh
[[ -v sayim[404] ]] && echo "404 anahtari var"
[[ -v sayim[999] ]] || echo "999 anahtari yok"
```

```
404 anahtari var
999 anahtari yok
```

Anahtar başına toplam almak da aynı desendir. Aşağıdaki döngü, her yola gönderilen toplam
bayt sayısını tek taramada hesaplar:

```sh
declare -A bayt
while read -r yol b; do
  bayt["$yol"]=$(( ${bayt["$yol"]:-0} + b ))
done < <(cut -d' ' -f7,10 erisim.log)

for y in "${!bayt[@]}"; do printf '%8d %s\n' "${bayt[$y]}" "$y"; done | sort -rn | head -5
```

```
   36120 /panel
   25230 /urun/12
   21990 /urun/45
   20480 /index.html
    7236 /api/veri
```

## Sürüm Bağımlılığı

İlişkisel diziler bash'in 4.0 sürümünden itibaren bulunur. Daha eski bir bash'te
`declare -A` tanınmaz — ve sonuç, sessiz olduğu için tehlikelidir.

```sh
#!/usr/bin/env bash
declare -A sayim
sayim[404]=4
echo "404 -> ${sayim[404]}"
```

Bash 4 ve sonrasında:

```
404 -> 4
```

Bash 3.2'de:

```
iliskisel.sh: line 2: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]
404 -> 4
```

Betik hata iletisi bastı ama **çalışmaya devam etti ve doğru görünen bir sonuç üretti.**
Nedeni şudur: bildirim başarısız olunca `sayim` sıradan bir dizinli dizi oldu ve `404`
anahtarı sayısal bir dizin olarak yorumlandı. Anahtarlar tam sayı olduğu sürece sonuç
tesadüfen doğru çıkar.

Anahtarlar dizgi olduğunda gizlenme biter:

```
metin-anahtar.sh: line 3: /api/veri: syntax error: operand expected (error token is "/api/veri")
```

Dizinli dizi, köşeli ayraç içindeki metni aritmetik ifade sayar ve yol adını
değerlendiremez.

Çözüm, gereksinimi betiğin başında sınamaktır. `BASH_VERSINFO` dizisi sürüm bileşenlerini
sayısal olarak tutar:

```sh
#!/usr/bin/env bash
if ((BASH_VERSINFO[0] < 4)); then
  echo "bu betik bash 4 veya ustunu gerektirir (bulunan: $BASH_VERSION)" >&2
  exit 4
fi
declare -A sayim
```

Betik, dördüncü sürümden eski bir yorumlayıcıyla çağrıldığında hemen durur. Aşağıdaki
çağrı, sürümü 3.2'de kalmış bir sistem kabuğunu açıkça seçer:

```sh
/bin/bash surum-sinama.sh
echo "cikis kodu: $?"
```

```
bu betik bash 4 veya ustunu gerektirir (bulunan: 3.2.57(1)-release)
cikis kodu: 4
```

Bu sınama, hatayı ortaya çıktığı yerde değil kaynağında bildirir. Belirli bir sürümü
gerektiren her betikte bulunmalıdır.

## POSIX Kabuğunda Dizi Yoktur

POSIX kabuk dili ne dizinli ne ilişkisel dizi tanımlar. Tek liste yapısı konumsal
parametrelerdir ve `set --` ile doldurulabilir:

```sh
set -- 2 3 4 5
echo "sayi=$#  ilk=$1  son=$4"
for s in "$@"; do printf '%s ' "$s"; done; echo
```

```
sayi=4  ilk=2  son=5
2 3 4 5 
```

Tek bir liste taşınabilir ve betiğin kendi argümanlarını ezer; ciddi bir kısıttır.

Anahtar başına sayım için POSIX çözümü kabukta veri yapısı kurmak değil, işi bunun için
tasarlanmış bir araca devretmektir. Alan tabanlı işleme aracının bir satırı, bu dersteki
döngünün tamamının yerini tutar ve her yerde aynı çalışır:

```sh
awk '{ sayim[$9]++ } END { for (k in sayim) print k, sayim[k] }' erisim.log | sort
```

```
200 17
201 1
301 1
302 1
304 1
403 2
404 4
500 3
```

Bu araç Metin İşleme konusunda ayrıntılı ele alınacak. Buradaki ders, seçimle ilgilidir:
**kabukta veri yapısı kurmak, verinin kabukta kalması gerektiğinde anlamlıdır;** yalnızca
sayım yapılacaksa dış araç hem daha hızlı hem daha taşınabilirdir.

## Özet

- Dizi elemanlarına `${dizi[i]}` ile erişilir; ayraçsız `$dizi` yalnızca ilk elemanı verir.
- `"${dizi[@]}"` elemanları ayrı kelimeler olarak genişletir; `[*]` tek metne indirger,
  tırnaksız biçim böler.
- Kabuk dizileri seyrek olabilir; eleman sayısıyla dizinler örtüşmeyebileceği için sayaçlı
  döngü yerine `"${!dizi[@]}"` kullanılır.
- `mapfile -t` bir akışı bölme ve genişletme uygulamadan diziye okur.
- İlişkisel diziler bash 4.0'dan itibaren bulunur; eksik olduğunda bildirim başarısız olur
  ama betik çalışmaya devam eder. `BASH_VERSINFO` ile sürüm sınaması zorunludur.
- POSIX kabuk dilinde dizi yoktur; anahtar başına sayım için alan tabanlı araç kullanılır.

## Sonraki Adım

Bu dersteki sayımlarda `$(( ... ))` ve `$( ... )` gösterimleri gerekçelendirilmeden
kullanıldı. Sonraki ders bu iki gösterimi tanımlar: kabukta aritmetiğin neden yalnızca tam
sayı olduğunu, ondalıklı hesabın nasıl yapıldığını, komut çıktısının değere çevrilirken
hangi karakterlerin kaybolduğunu ve bu dönüşümün maliyetini.
