---
title: Döngüler
source: 'https://academia.sh/tr/kurslar/kabuk-programlama/donguler'
course: 'Kabuk Programlama'
language: tr
updated: '2026-08-17T18:10:01+00:00'
license: 'CC BY-SA 4.0'
---

# Döngüler

Liste, sayaç ve koşul tabanlı yineleme, dosya adları üzerinde güvenli dönme, satır satır okumanın doğru biçimi ve döngü denetimi.

Rapor şu an tek bir liste üretiyor. Durum kodu sınıflarının her biri için ayrı sayım
istendiğinde aynı boru hattını dört kez elle yazmak gerekir. Programlama Temelleri
kursunda bu, yinelemenin klasik gerekçesiydi.

Kabuktaki döngüler aynı yapıları kurar, ama listenin nereden geldiği kabuğun genişletme
kurallarına bağlıdır. Bu ders döngü biçimlerini ve — kabuk programlamanın en sık yanlış
yazılan parçası olan — dosyayı satır satır okuma desenini ele alır.

## Liste Üzerinde Dönme

`for` döngüsü, kendisine verilen kelime listesinin her elemanı için gövdeyi çalıştırır.

```sh
for sinif in 2 3 4 5; do
  adet=$(cut -d' ' -f9 erisim.log | grep -c "^${sinif}")
  echo "${sinif}xx -> $adet"
done
```

```
2xx -> 18
3xx -> 3
4xx -> 6
5xx -> 3
```

`$( ... )` gösterimi bir komutun çıktısını değere çevirir; ayrıntısı bu konunun son
dersinde ele alınacak.

Listedeki "kelime" kavramı, önceki derslerde kurulan kelime bölme kavramıyla aynıdır.
Liste bir değişkenden geliyorsa, tırnak kullanımı doğrudan döngünün tur sayısını belirler:

```sh
kodlar="200 404 500"
for k in $kodlar;   do printf '<%s> ' "$k"; done; echo
for k in "$kodlar"; do printf '<%s> ' "$k"; done; echo
```

```
<200> <404> <500> 
<200 404 500> 
```

Bu, kelime bölmenin bilinçli olarak istendiği ender durumlardan biridir. Yine de değeri
tek bir dizgide tutup bölünmesine güvenmek kırılgandır; birden çok değer taşınacaksa dizi
kullanmak doğru araçtır. Diziler bu konunun yedinci dersinin konusudur.

## Dosya Adları Üzerinde Dönme

Bir dizindeki dosyalar üzerinde dönmenin doğru yolu, yol adı kalıbını doğrudan listeye
yazmaktır:

```sh
mkdir -p kutukler; : > 'kutukler/a.log'; : > 'kutukler/b c.log'
for f in kutukler/*.log; do echo "  [$f]"; done
```

```
  [kutukler/a.log]
  [kutukler/b c.log]
```

Boşluk içeren ad tek parça kaldı; çünkü yol adı genişletmesinin sonucu kelime bölmeye
uğramaz. Bu, ikinci derste kurulan kuralın pratik karşılığıdır.

Aynı işi `for f in $(ls kutukler)` biçiminde yazmak yanlıştır: `ls` çıktısı bir metindir
ve kelime bölmeye uğrar; boşluk içeren her ad parçalanır. Kabukta dosya listesi üretmenin
aracı `ls` değil, yol adı genişletmesidir.

Kalıbın hiçbir dosyayla eşleşmemesi ayrı bir tuzaktır:

```sh
for f in kutukler/*.yok; do echo "  [$f]"; done
```

```
  [kutukler/*.yok]
```

Eşleşme yoksa kabuk kalıbı harfi harfine bırakır ve döngü bir kez, var olmayan bir dosya
adıyla döner. İki çözüm vardır. Taşınabilir olanı, gövdenin başına varlık sınaması
koymaktır:

```sh
for f in kutukler/*.yok; do
  [ -e "$f" ] || continue
  echo "  [$f]"
done
```

Bash'e özgü olanı `nullglob` seçeneğidir; eşleşmeyen kalıp boş listeye genişler ve döngü
hiç dönmez:

```sh
shopt -s nullglob
for f in kutukler/*.yok; do echo "  [$f]"; done
shopt -u nullglob
```

Seçenek genel bir ayardır ve etkin olduğu sürece tüm kalıpları etkiler; betiğin başında
açılıp bırakılması, ilerideki satırlarda beklenmedik davranışa yol açabilir.

## Sayaçlı Döngüler

Sabit sayıda tur için üç yazım vardır.

**Ayraç genişletmesi** derleme zamanında sabit bir liste üretir:

```sh
for i in {1..5}; do printf '%s ' "$i"; done; echo
```

```
1 2 3 4 5 
```

Ayraç genişletmesi değişken içeremez — `{1..$n}` beklendiği gibi çalışmaz, çünkü ayraç
genişletmesi değişken genişletmesinden **önce** uygulanır. Bu, genişletme sırasının
gözlemlenebilir sonuçlarından biridir.

**C biçimli döngü** bash eklentisidir ve değişken sınır alabilir:

```sh
for ((i = 1; i <= 5; i++)); do printf '%s ' "$i"; done; echo
```

```
1 2 3 4 5 
```

**Dizi üreten komut**, taşınabilir üçüncü yoldur: `for i in $(seq 1 "$n")`. Komut
çağırması nedeniyle en pahalı seçenektir, ama POSIX kabuk dilinde çalışır.

## Koşul Tabanlı Döngüler

`while`, koşul komutu 0 döndürdüğü sürece; `until` sıfırdan farklı döndürdüğü sürece
gövdeyi yineler.

```sh
sayac=0
until [ "$sayac" -ge 3 ]; do
  echo "sayac=$sayac"
  sayac=$((sayac + 1))
done
```

```
sayac=0
sayac=1
sayac=2
```

İkisi birbirinin yerine kullanılabilir; `until`, koşulun değillemesini yazmaktan kurtarır
ve okunurluğu artırdığı durumlarda yeğlenir.

## Dosyayı Satır Satır Okumak

Kabuk programlamada en sık yanlış yazılan desen budur. Doğru biçim üç parçadan oluşur ve
her parçanın ayrı bir gerekçesi vardır:

```sh
while IFS= read -r satir; do
  ...
done < dosya
```

**`-r` seçeneği** ters bölü işlemesini kapatır. Bu seçenek olmadan `read`, ters bölüyü bir
kaçış karakteri sayar ve veriyi bozar.

**`IFS=` ataması** satırın başındaki ve sonundaki boşlukların kırpılmasını engeller.

**Yönlendirme, boru değil.** Boru hattının sağ ucundaki döngü alt kabukta çalışır ve
atadığı değişkenler kaybolur; bu, Boru Hattı dersinde gösterilmişti.

Üç parçanın etkisi ölçülebilir. Aşağıdaki dosya üç satırdır: ilkinde iki boşluk, ikincisi
ters bölüyle başlar, üçüncüsünün iki ucunda boşluk vardır.

```sh
printf 'bir  iki\n\\ters bolulu\n  bosluklu kenar  \n' > garip.txt
while read satir; do printf '<%s>\n' "$satir"; done < garip.txt
```

```
<bir  iki>
<ters bolulu>
<bosluklu kenar>
```

```sh
while IFS= read -r satir; do printf '<%s>\n' "$satir"; done < garip.txt
```

```
<bir  iki>
<\ters bolulu>
<  bosluklu kenar  >
```

İlk yazımda ters bölü yutuldu ve kenar boşlukları kırpıldı. İkincisi dosyayı olduğu gibi
verdi.

Dördüncü bir ayrıntı, son satırda satır sonu bulunmamasıdır. `read` satır sonu görmeden
dosya sonuna ulaşırsa okuduğunu değişkene yazar ama sıfırdan farklı kod döndürür; döngü
koşulu bu kodu yanlış anlar ve son satır işlenmez:

```sh
printf 'birinci\nikinci' > eksik.txt
while IFS= read -r s; do echo "okundu: $s"; done < eksik.txt
```

```
okundu: birinci
```

Koşula bir ek yapılır: değişken boş değilse döngü bir tur daha döner.

```sh
while IFS= read -r s || [ -n "$s" ]; do echo "okundu: $s"; done < eksik.txt
```

```
okundu: birinci
okundu: ikinci
```

Bu kalıp, dış kaynaklı verinin okunduğu her betikte gereklidir; satır sonuyla bitmeyen
dosyalar nadir değildir.

## Satırı Alanlara Bölerek Okumak

`read` birden çok değişken alırsa satırı `IFS`'e göre böler ve son değişkene kalan her
şeyi verir. Kütüğün alanları boşlukla ayrıldığı için doğrudan okunabilir:

```sh
head -3 erisim.log | while read -r adres _ _ _ _ yontem yol _ kod bayt; do
  printf '%-12s %-4s %-18s %s %s\n' "$adres" "${yontem#\"}" "$yol" "$kod" "$bayt"
done
```

```
10.0.0.12    GET  /index.html        200 5120
10.0.0.31    GET  /statik/stil.css   200 2048
10.0.0.12    GET  /urun/12           200 8410
```

`_` adı bir sözleşmedir, dil öğesi değil: ilgilenilmeyen alanlar aynı değişkene atanır.
`${yontem#\"}` gösterimi baştaki tırnağı siler; dizgi işleme gösterimleri Aritmetik ve
Komut Yerine Koyma dersinde toparlanacak.

Bu döngü, alan sayısı sabit olan veriler için yeterlidir. Alan sayısı değişken olduğunda
ya da hesaplama gerektiğinde alan tabanlı bir araç daha uygundur; Metin İşleme konusunda
aynı iş tek satıra inecek.

## Döngü Denetimi

`break` içinde bulunduğu döngüyü sonlandırır, `continue` turu atlar. İkisi de sayı
argümanı alarak dış döngülere etki edebilir.

```sh
for k in 200 301 404 500 xyz 200; do
  case "$k" in
    [0-9][0-9][0-9]) : ;;
    *) echo "gecersiz kod, atlaniyor: $k"; continue ;;
  esac
  if [ "$k" -ge 500 ]; then echo "sunucu hatasi bulundu: $k"; break; fi
  echo "islendi: $k"
done
```

```
islendi: 200
islendi: 301
islendi: 404
sunucu hatasi bulundu: 500
```

`break 2` iki düzey dışarı çıkar:

```sh
for a in 1 2; do
  for b in x y; do
    [ "$b" = y ] && break 2
    echo "$a$b"
  done
done
```

```
1x
```

Sayılı `break` okunurluğu hızla bozar; iki düzeyden fazlasında döngüyü bir fonksiyona
alıp `return` kullanmak daha anlaşılır olur. Fonksiyonlar sonraki dersin konusudur.

## Betiğe Uygulama

`rapor.sh` ikinci bir bölüm kazanır: durum kodu sınıflarının dağılımı.

```sh
kutuk=erisim.log

echo "== Durum kodu siniflari =="
for sinif in 2 3 4 5; do
  adet=$(cut -d' ' -f9 "$kutuk" | grep -c "^${sinif}")
  case "$sinif" in
    2) ad="basarili"       ;;
    3) ad="yonlendirme"    ;;
    4) ad="istemci hatasi" ;;
    5) ad="sunucu hatasi"  ;;
  esac
  printf '  %sxx %-16s %3d\n' "$sinif" "$ad" "$adet"
done
```

```
== Durum kodu siniflari ==
  2xx basarili          18
  3xx yonlendirme        3
  4xx istemci hatasi     6
  5xx sunucu hatasi      3
```

Sayıların toplamı otuzdur; kütükteki satır sayısına eşittir. Bu tür bir iç tutarlılık
sınaması, rapor betiklerinin doğruluğunu ucuz biçimde denetlemenin yoludur.

## Özet

- `for` listesi, kabuğun genişletme kurallarıyla oluşur; tırnaksız değişken bölünür,
  tırnaklı bölünmez.
- Dosya listesi `ls` çıktısından değil yol adı genişletmesinden üretilir; eşleşme yoksa
  kalıp harfi harfine kalır ve `[ -e "$f" ] || continue` ya da `nullglob` gerekir.
- Ayraç genişletmesi değişken alamaz, çünkü değişken genişletmesinden önce uygulanır.
- Satır satır okumanın doğru biçimi `while IFS= read -r satir; do ... done < dosya`
  yazımıdır; boru kullanılırsa döngü alt kabuğa düşer.
- Satır sonuyla bitmeyen dosyalarda son satır ancak `|| [ -n "$satir" ]` ekiyle işlenir.

## Sonraki Adım

Betik büyüdükçe aynı iş — hata bildirme, bölüm başlığı yazma, bir alanı sayma — birden
çok yerde tekrar ediyor. Sonraki ders fonksiyonları ele alır: kabukta fonksiyon tanımının
ne olduğunu, argümanların nasıl geçtiğini, `return` ile `exit` arasındaki farkı ve
kabuğun kapsam modelinin Programlama Temelleri kursundakinden hangi noktada ayrıldığını.
