---
title: 'Değişkenler ve Tırnak Kuralları'
source: 'https://academia.sh/tr/kurslar/kabuk-programlama/degiskenler-ve-tirnak-kurallari'
course: 'Kabuk Programlama'
language: tr
updated: '2026-08-17T18:10:02+00:00'
license: 'CC BY-SA 4.0'
---

# Değişkenler ve Tırnak Kuralları

Atama sözdizimi, genişletme sırası, kelime bölme ve yol adı genişletmesi, üç alıntılama biçimi ve öntanımlı değer gösterimleri.

Betikteki kütük adı şimdilik sabit yazılı. Onu bir değişkene almak ilk bakışta düzen
meselesi görünür. Kabukta ise bu, dilin en çok hata üreten alanına girmek demektir:
bir değişkenin genişletilmesi tek bir işlem değildir, birkaç aşamalı bir süreçtir ve
aşamaların hangisinin uygulanacağı tırnak kullanımına bağlıdır.

Programlama Temelleri kursunda değişken, bir değere bağlanan addı; okunduğunda o değeri
verirdi. Kabukta durum farklıdır: değişken okunduğunda ortaya çıkan metin, komut satırının
geri kalanıyla birlikte yeniden çözümlenir. Bu dersin konusu tam olarak o yeniden
çözümlemedir.

## Atama

Atama, eşittir işaretinin iki yanında boşluk bırakılmadan yazılır.

```sh
ad = deger
```

```
bash: ad: command not found
```

Kabuk `ad` kelimesini komut adı, `=` ve `deger` kelimelerini argüman sandı. Kabuk
satırını önce boşluğa göre kelimelere ayırdığı için başka türlü davranamazdı. Doğru
yazımda boşluk yoktur:

```sh
ad=deger
echo "[$ad] [${ad}] [${ad}suz]"
```

```
[deger] [deger] [degersuz]
```

Süslü ayraçlı biçim, ad ile onu izleyen metnin sınırını belirtir. `$adsuz` yazılsaydı
kabuk `adsuz` adlı bir değişken arardı.

Kabukta değişkenlerin tipi yoktur; her değer bir karakter dizisidir. `sayi=5` ataması bir
tam sayı üretmez, iki karakterlik bir dizi üretir. Sayısal işlem gerektiğinde ayrı bir
gösterim kullanılır; bu, Aritmetik ve Komut Yerine Koyma dersinin konusudur.

## Genişletmeden Sonra Ne Olur

Bir değişken genişletildiğinde iş bitmez. Kabuk, tırnaksız genişletmenin sonucuna iki
işlem daha uygular:

1. **Kelime bölme (word splitting).** Sonuç metni, `IFS` değişkenindeki karakterlere
   göre kelimelere ayrılır. `IFS`'in öntanımlı değeri boşluk, sekme ve satır sonudur.
2. **Yol adı genişletmesi (pathname expansion).** Kelimelerde `*`, `?`, `[...]`
   karakterleri varsa eşleşen dosya adlarıyla değiştirilir.

İki işlemin sonucu gözlemlenebilir. Aşağıdaki yardımcı, aldığı argüman sayısını ve her
argümanı ayrı ayrı yazar:

```sh
say() { printf 'argüman sayisi: %d\n' "$#"; printf '  <%s>\n' "$@"; }
```

```sh
metin="iki   bosluklu"
say $metin
say "$metin"
```

```
argüman sayisi: 2
  <iki>
  <bosluklu>
argüman sayisi: 1
  <iki   bosluklu>
```

Tırnaksız genişletmede iki kelime, tırnaklı genişletmede tek kelime oluştu. Aradaki üç
boşluk da tırnaksız durumda kayboldu — kelime bölme ayırıcıları saklamaz.

## Tırnaksız Genişletmenin Bedeli

Bu davranışın betiklerdeki karşılığı somuttur. Boşluk içeren bir dosya adı düşünün:

```sh
kutuk="erisim kutugu.log"
say $kutuk
say "$kutuk"
```

```
argüman sayisi: 2
  <erisim>
  <kutugu.log>
argüman sayisi: 1
  <erisim kutugu.log>
```

Tırnaksız yazımda komut, var olmayan iki dosya adı aldı. `rm $kutuk` gibi bir satırda bu,
yanlış dosyanın silinmesi anlamına gelir.

Yol adı genişletmesi ikinci bir katman ekler. Değişkenin içinde kalıp karakteri varsa,
tırnaksız genişletme dosya sistemine bakar:

```sh
cd "$(mktemp -d)"          # yalnızca iki dosyanın bulunduğu boş bir dizin
: > "erisim kutugu.log"
: > yok.log

kalip="*.log"
say $kalip
say "$kalip"
```

```
argüman sayisi: 2
  <erisim kutugu.log>
  <yok.log>
argüman sayisi: 1
  <*.log>
```

Sıraya dikkat edin: değişkenin değeri `*.log` idi; genişletme, kelime bölme ve yol adı
genişletmesinden sonra iki dosya adı ortaya çıktı. Üstelik `erisim kutugu.log` tek
argüman olarak geldi — çünkü **yol adı genişletmesinin sonucu kelime bölmeye
uğramaz.** Bölme yalnızca değişkenin kendi değerine uygulanır.

Buradan kursun geri kalanında geçerli olacak kural çıkar:

> **Değişken genişletmeleri her zaman çift tırnak içine alınır.** Tırnaksız bırakmak,
> kelime bölme ya da yol adı genişletmesi bilinçli olarak isteniyorsa yapılır.

Bu kural `"$var"`, `"$@"`, `"$(komut)"` ve `"${dizi[@]}"` için de geçerlidir.

## Üç Alıntılama Biçimi

**Çift tırnak** genişletmeleri uygular ama kelime bölme ve yol adı genişletmesini
engeller. Değişken, komut ve aritmetik genişletme içeride çalışır.

**Tek tırnak** hiçbir şeyi genişletmez; içerideki her karakter harfi harfine geçer. Tek
tırnak içinde tek tırnak kullanılamaz — ters bölü bile onu kaçırmaz.

**Ters bölü**, kendisinden sonraki tek karakteri özel anlamından arındırır. Çift tırnak
içinde yalnızca `$`, `` ` ``, `"`, `\` ve satır sonu için etkilidir; diğer karakterlerin
önünde harfi harfine kalır.

```sh
metin="iki   bosluklu"
echo $metin
echo "$metin"
echo '$metin'
```

```
iki bosluklu
iki   bosluklu
$metin
```

İlk satırda `echo` iki ayrı argüman aldı ve aralarına tek boşluk koyarak yazdı; ikinci
satırda boşluklar korundu; üçüncüde genişletme hiç olmadı.

Düzenli ifadeler ve `sed` kalıpları tek tırnak içinde yazılır: kalıplarda geçen `$`, `*`
ve `\` karakterlerinin kabuk tarafından yorumlanması istenmez. Bu kural Metin İşleme
konusunun tamamında geçerli olacak.

## IFS ve Bilinçli Bölme

`IFS` (internal field separator) değişkeni, kelime bölmenin hangi karakterlerde
yapılacağını belirler. Değiştirmek, ayrılmış bir satırı alanlarına bölmenin yollarından
biridir:

```sh
satir="10.0.0.12:404:512"
IFS=:
say $satir
```

```
argüman sayisi: 3
  <10.0.0.12>
  <404>
  <512>
```

`IFS` genel bir ayardır; değiştirildikten sonra o kabuktaki tüm tırnaksız genişletmeleri
etkiler. Eski değerine döndürmeyi unutmak, betiğin ilerideki satırlarında açıklaması güç
hatalar üretir. Doğru desen, `IFS`'i yalnızca tek bir komut için ayarlamaktır:

```sh
IFS=: read -r adres kod bayt <<< "$satir"
```

Komuttan önce yazılan atama yalnızca o komutun ortamında geçerlidir; komut bitince eski
değer geri gelir. Bu desen Döngüler dersinde kütüğü satır satır okurken kullanılacak.

## Öntanımlı Değer Gösterimleri

Kabuk, tanımsız veya boş değişkenleri yerinde ele almak için bir gösterim ailesi sunar.
İki nokta üst üste karakterinin varlığı, "boş" değerin de eksik sayılıp sayılmayacağını
belirler.

| Gösterim | Değişken tanımsızsa | Değişken boşsa |
|---|---|---|
| `${v-yedek}` | `yedek` | boş dizi |
| `${v:-yedek}` | `yedek` | `yedek` |
| `${v=yedek}` | atar ve `yedek` verir | boş dizi |
| `${v:=yedek}` | atar ve `yedek` verir | atar ve `yedek` verir |
| `${v:?ileti}` | hata verip çıkar | hata verip çıkar |
| `${v:+deger}` | boş dizi | boş dizi |
| `${#v}` | 0 | 0 |

```sh
unset KUTUK
echo "1 tanimsiz, :- ile: [${KUTUK:-erisim.log}]"
KUTUK=""
echo "2 bos, :- ile: [${KUTUK:-erisim.log}]"
echo "3 bos, -  ile: [${KUTUK-erisim.log}]"
```

```
1 tanimsiz, :- ile: [erisim.log]
2 bos, :- ile: [erisim.log]
3 bos, -  ile: []
```

Ayrım önemlidir: bir seçeneğin bilinçli olarak boş bırakılması ile hiç verilmemesi farklı
durumlardır. `:-` ikisini aynı sayar, `-` ayırır.

`:?` biçimi zorunlu değişkenleri bildirmenin en kısa yoludur:

```sh
unset ZORUNLU
echo "[${ZORUNLU:?tanimlanmali}]"
```

```
bash: ZORUNLU: tanimlanmali
```

Betik bu noktada sıfırdan farklı kodla durur. Hata Yönetimi dersinde bu gösterim katı
kiple birlikte kullanılacak.

## Ortam Değişkenleri ve Kapsam

Kabuk değişkenleri öntanımlı olarak yalnızca o kabuğa aittir. `export`, değişkeni
**ortama (environment)** koyar; o noktadan sonra başlatılan alt süreçler onu görür.

```sh
export DIL=tr
bash -c 'echo "alt surecte DIL=$DIL"'
YEREL=x
bash -c 'echo "alt surecte YEREL=[${YEREL-yok}]"'
```

```
alt surecte DIL=tr
alt surecte YEREL=[yok]
```

Aktarım tek yönlüdür: alt süreç ortamı değiştirse bile üst süreç bundan etkilenmez.
Boru Hattı dersindeki kural burada da geçerlidir.

`readonly` bir değişkeni değiştirilemez yapar:

```sh
readonly SABIT=5
SABIT=6
```

```
bash: SABIT: readonly variable
```

Adlandırma sözleşmesi yaygındır ve uyulması yararlıdır: **ortama giren ve dış dünyayla
paylaşılan adlar büyük harfle, betiğe özgü adlar küçük harfle** yazılır. Küçük harf
kullanmak ayrıca `PATH`, `HOME`, `IFS` gibi kabuk değişkenlerinin kazara ezilmesini
önler.

## Betiğe Uygulama

`rapor.sh` betiği, sabit yazılı kütük adından kurtulur:

```sh
#!/usr/bin/env bash
# rapor.sh — erisim kutugunden ozet rapor uretir.

kutuk="${KUTUK:-erisim.log}"

echo "== Kutuk: $kutuk =="
echo "== En cok istenen yollar =="
cut -d' ' -f7 "$kutuk" | sort | uniq -c | sort -rn | head -5
```

```
== Kutuk: erisim.log ==
== En cok istenen yollar ==
   6 /api/veri
   4 /yok.html
   4 /index.html
   3 /urun/45
   3 /urun/12
```

Üç karar birlikte alındı: ad bir değişkene çekildi, ortamdan gelen `KUTUK` değeri
öncelikli kılındı ve `"$kutuk"` genişletmesi tırnaklandı. Üçüncüsü olmadan, boşluk içeren
bir yol verildiğinde betik sessizce yanlış dosyayı okumaya çalışırdı.

## Özet

- Atama, eşittir işaretinin iki yanında boşluk bırakmaz; kabuk satırı kelimelere ayırdığı
  için başka türlü ayrıştıramaz.
- Tırnaksız genişletmenin sonucuna kelime bölme ve yol adı genişletmesi uygulanır; yol
  adı genişletmesinin sonucu yeniden bölünmez.
- Değişken genişletmeleri her zaman çift tırnak içine alınır; tırnaksız bırakmak bilinçli
  bir karardır.
- Çift tırnak genişletir ve bölmeyi engeller, tek tırnak hiçbir şeyi genişletmez, ters
  bölü tek karakteri arındırır.
- `-` ile `:-` arasındaki fark, boş değerin eksik sayılıp sayılmamasıdır; `:?` zorunlu
  değişkeni bildirir.
- `export` değişkeni alt süreçlere aktarır; aktarım tek yönlüdür.

## Sonraki Adım

Kütük adı artık ortam değişkeninden gelebiliyor, ama betiği çağıran kişi için doğal olan
yol bu değildir: `./rapor.sh erisim.log` yazmak beklenir. Sonraki ders betiğe komut
satırından değer geçirmeyi ele alır — konumsal parametreler, argüman listesinin
tırnaklanması ve `"$@"` ile `"$*"` arasındaki, boşluklu argümanlarda ortaya çıkan fark.
