---
title: 'Aritmetik ve Komut Yerine Koyma'
source: 'https://academia.sh/tr/kurslar/kabuk-programlama/aritmetik-ve-komut-yerine-koyma'
course: 'Kabuk Programlama'
language: tr
updated: '2026-08-17T18:10:01+00:00'
license: 'CC BY-SA 4.0'
---

# Aritmetik ve Komut Yerine Koyma

Tam sayı aritmetiği ve tuzakları, aritmetik komutun ters çıkış kodu, ondalıklı hesabın dışarıya devri, komut çıktısının değere çevrilmesi.

Önceki iki derste `$(( ... ))` ve `$( ... )` gösterimleri gerekçelendirilmeden kullanıldı.
İkisi de kabuğun temel araçlarıdır ve ikisinin de sessizce yanlış sonuç üreten köşeleri
vardır.

Değişkenler dersinde kurulan ilke geçerliliğini koruyor: kabukta her değer bir karakter
dizisidir. Bu iki gösterim, o dizileri geçici olarak başka bir alana taşıyıp geri getirir —
biri sayı alanına, diğeri komut çıktısı alanına.

## Aritmetik Genişletme

`$(( ifade ))` gösterimi, içindeki ifadeyi tam sayı olarak değerlendirir ve sonucu metin
olarak yerine koyar.

```sh
echo "$(( 7 / 2 )) $(( -7 / 2 )) $(( 7 % 2 )) $(( 2 ** 10 ))"
```

```
3 -3 1 1024
```

Bölme **sıfıra doğru kırpar**: $7/2$ için 3, $-7/2$ için $-3$ verir. Aşağı yuvarlama
yapan dillerden farklıdır; negatif sayılarla çalışırken sonuç ayrımı önemlidir.

İfade içinde değişkenler dolar işareti olmadan yazılabilir; ayraç içi zaten sayı alanıdır:

```sh
a=6; b=4
echo "$(( a + b )) $(( $a * $b ))"
```

```
10 24
```

Ayraç içinde boşluk serbesttir ve kelime bölme uygulanmaz. `$(( 1+2 * 3 ))` ifadesi 7
verir; öncelik kuralları Programlama Temelleri kursundaki işleç önceliğiyle aynıdır.

## Taban Tuzağı

Kabuk, sıfırla başlayan sayıyı **sekizlik (octal)** kabul eder. Sıfır dolgulu alanlardan
gelen değerler — saat, dakika, sıra numarası — bu yüzden hata üretir:

```sh
echo "$(( 08 ))"
```

```
bash: 08: value too great for base (error token is "08")
```

`08` sekizlik tabanda geçerli değildir. Tabanı açıkça bildirmek gerekir:

```sh
echo "$(( 10#08 ))"
```

```
8
```

`10#` öneki değeri onluk tabanda okur. Dış kaynaktan gelen ve sıfır dolgulu olabilecek
her değerde kullanılmalıdır.

## Aritmetik Komut ve Ters Çıkış Kodu

`(( ifade ))` bir genişletme değil, bir komuttur: değeri yerine koymaz, yalnızca hesaplar
ve bir çıkış kodu üretir. Kod, **değerin tersidir**: sonuç sıfırdan farklıysa 0 (başarı),
sonuç sıfırsa 1 (başarısızlık).

```sh
(( 1 + 1 )); echo "sonuc 2 -> kod=$?"
(( 0 ));     echo "sonuc 0 -> kod=$?"
```

```
sonuc 2 -> kod=0
sonuc 0 -> kod=1
```

Bu tersleme rastgele değil, iki sözleşmenin uzlaştırılmasıdır: C benzeri dillerde sıfırdan
farklı değer "doğru"dur, kabukta ise 0 kodu "başarı"dır. Sonuç, aritmetik koşulları doğal
biçimde yazılabilir kılar:

```sh
(( 5 > 3 )) && echo "karsilastirma dogru"
```

```
karsilastirma dogru
```

Tuzak, katı kip altında ortaya çıkar. `(( sayac++ ))` ifadesi `sayac` sıfırken 1 kodu
döndürür; `set -e` etkin bir betikte bu, betiği durdurur. Sayaç artırmanın güvenli
yazımı `sayac=$(( sayac + 1 ))` biçimidir. Bu tuzak Hata Yönetimi dersinde yeniden ele
alınacak.

`(( ))` içinde `++`, `--`, `+=` gibi işleçler kullanılabilir:

```sh
sayac=0; (( sayac++ )); (( sayac += 5 )); echo "sayac=$sayac"
```

```
sayac=6
```

Eski betiklerde aynı iş için `let` ve `expr` görülür. `let` bash eklentisidir ve
`(( ))` ile eşdeğerdir. `expr` ayrı bir programdır; her çağrıda bir süreç yaratır ve
işleçlerinin kabuk tarafından yorumlanmaması için kaçırılması gerekir. Yeni betiklerde
ikisi de gerekli değildir.

## Ondalıklı Hesap Kabukta Yoktur

Kabuk aritmetiği yalnızca tam sayıdır. Ondalıklı sonuç gerektiğinde iş dışarıya devredilir.

```sh
awk 'BEGIN { printf "%.2f\n", 4 / 30 * 100 }'
```

```
13.33
```

Rasgele duyarlıkta hesap yapan bir hesap makinesi aracı da kullanılabilir, ancak
`scale` ayarının **her bölme işleminde** uygulandığı unutulmamalıdır:

```sh
echo 'scale=2; 4 / 30 * 100' | bc
echo 'scale=2; 4 * 100 / 30' | bc
```

```
13.00
13.33
```

İlk yazımda bölme önce yapıldı ve sonuç 0.13'e kırpıldı; çarpma bu kırpılmış değerle
sürdü. İşlem sırasını çarpma bölmeden önce gelecek biçimde kurmak, sabit duyarlıklı
hesapta genel bir kuraldır.

Üçüncü yol, ölçeklendirilmiş tam sayı aritmetiğidir. Ondalık noktayı elle yerleştirmek,
dış araç çağırmadan bir hane duyarlık verir:

```sh
pay=4; toplam=30
printf '%d.%d\n' $(( pay * 1000 / toplam / 10 )) $(( pay * 1000 / toplam % 10 ))
```

```
13.3
```

Bu yöntem yuvarlama değil kırpma yapar. Rapor niteliğindeki çıktılarda yeterlidir; parasal
ya da bilimsel hesapta değildir.

## Komut Yerine Koyma

`$( komut )` gösterimi, komutu çalıştırır, standart çıktısını yakalar ve o metni yerine
koyar.

```sh
adet=$(wc -l < erisim.log)
echo "[$adet]"
```

```
[      30]
```

Baştaki boşluklar geldi — bu, birinci derste değinilen hizalama farkıdır. Aritmetik
genişletme boşlukları soğurur:

```sh
adet=$(( $(wc -l < erisim.log) ))
echo "[$adet]"
```

```
[30]
```

Bu iç içe yazım, komut çıktısını sayıya çevirmenin standart yoludur.

## Yerine Koymanın Uyguladığı Dönüşümler

Üç davranış bilinmelidir.

**Sondaki satır sonları silinir.** Komutun çıktısındaki tüm sondaki satır sonları atılır;
aradakiler korunur.

```sh
d=$(printf 'a\n\n\n')
printf '<%s>\n' "$d"
```

```
<a>
```

Bu davranış çoğu zaman istenendir, ama satır sonu anlamlı olan verilerde kayba yol açar.

**Tırnaksız yazım bölünür.** Değişken genişletmesinde geçerli olan kural burada da
geçerlidir:

```sh
say() { printf 'sayi=%d\n' "$#"; }
say $(head -2 erisim.log)
say "$(head -2 erisim.log)"
```

```
sayi=20
sayi=1
```

Tırnaksız yazımda iki satır yirmi kelimeye bölündü. **Komut yerine koyma her zaman
tırnaklanır.**

**Çıkış kodu atamayla kaybolmaz ama gizlenebilir.** Yalnızca yerine koyma yapan bir atama,
komutun kodunu `$?` içinde bırakır:

```sh
d=$(grep '999' erisim.log); echo "kod=$?"
```

```
kod=1
```

Ancak atamanın önünde `local`, `export` ya da `declare` varsa kod o komuta ait olur ve
gerçek sonuç görünmez; bu tuzak Fonksiyonlar ve Kapsam dersinde gösterilmişti.

## Yazım Biçimleri

`$( ... )` yazımının eski karşılığı ters tırnaktır. İki nedenle yeğlenmez: iç içe
kullanımda her düzey için ters bölü gerekir ve ters bölünün ters tırnak içindeki anlamı
farklıdır. `$( ... )` iç içe yazımda hiçbir kaçış istemez:

```sh
echo "en cok istenen: $(cut -d' ' -f7 "$(echo erisim.log)" | sort | uniq -c | sort -rn | head -1)"
```

```
en cok istenen:    6 /api/veri
```

Bir dosyanın tamamını okumak için bash `$(< dosya)` kısayolunu sunar; süreç yaratmadığı
için `$(cat dosya)` yazımından ucuzdur:

```sh
echo "[$(< tek.txt)]"
```

```
[merhaba]
```

## Maliyet

Komut yerine koyma bir alt kabuk ve genellikle bir dış süreç yaratır. Otuz satırlık bir
kütükte bu görünmez; döngü içinde satır başına bir çağrı yapan bir betikte, iş yükünün
tamamını süreç yaratma oluşturabilir.

Kural: **döngü gövdesinde komut yerine koyma varsa, aynı işi tek bir dış araç çağrısıyla
yapmanın yolu aranır.** Bir sonraki konunun tamamı bu ilkenin uygulanmasıdır.

## Betiğe Uygulama

`rapor.sh`, bir özet bloğu ve yüzde sütunu kazanır:

```sh
kutuk=erisim.log

yuzde() {                       # yuzde PAY TOPLAM -> "13.3"
  local pay="$1" toplam="$2"
  (( toplam == 0 )) && { echo "0.0"; return; }
  printf '%d.%d' $(( pay * 1000 / toplam / 10 )) $(( pay * 1000 / toplam % 10 ))
}

istek=$(( $(wc -l < "$kutuk") ))
bayt=$(awk '{ t += $10 } END { print t + 0 }' "$kutuk")

bolum "Kutuk: $kutuk"
printf '  istek sayisi : %d\n' "$istek"
printf '  toplam bayt  : %d\n' "$bayt"
printf '  istek basina : %d bayt\n' $(( istek > 0 ? bayt / istek : 0 ))
```

```sh
./rapor.sh -n 3
```

```

== Kutuk: erisim.log ==
  istek sayisi : 30
  toplam bayt  : 117780
  istek basina : 3926 bayt

== En cok istenen 3 yol ==
   6 /api/veri
   4 /yok.html
   4 /index.html

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

`$(( istek > 0 ? bayt / istek : 0 ))` yazımındaki üçlü işleç, sıfıra bölmeyi önler. Kabuk
aritmetiğinde sıfıra bölme, betiği durduran bir hatadır; bölen her zaman sınanmalıdır.

Yüzdelerin toplamı 100,0 çıkıyor ve sayıların toplamı istek sayısına eşit. Bu iç tutarlılık,
raporun doğruluğunun en ucuz sınamasıdır.

## Özet

- `$(( ))` tam sayı aritmetiği yapar, sıfıra doğru kırpar ve içinde değişkenler dolar
  işaretsiz yazılabilir; sıfırla başlayan sayılar sekizlik sayılır, `10#` öneki gerekir.
- `(( ))` bir komuttur ve çıkış kodu değerin tersidir; sıfır sonuç başarısızlık bildirir.
- Ondalıklı hesap kabukta yoktur; dış araca devredilir ya da ölçeklendirilmiş tam sayıyla
  yapılır.
- Komut yerine koyma sondaki satır sonlarını siler ve tırnaksız yazımda bölünür; her zaman
  tırnaklanır.
- Her yerine koyma bir alt kabuk maliyetidir; döngü gövdesindeki çağrılar toplu bir dış
  araç çağrısıyla değiştirilmelidir.

## Sonraki Adım

Bu konu betiğin iskeletini tamamladı: yorumlayıcı bildirimi, argüman arayüzü, girdi
sınamaları, fonksiyonlar, döngüler ve hesap. Betik çalışıyor, ama yaptığı işin çoğunu
kaba araçlarla yapıyor: yolları `cut` ile ayırıyor, durum kodlarını `grep -c` ile sayıyor
ve her sayım için kütüğü baştan okuyor.

Sonraki konu bu işleri asıl araçlarına devreder. Düzenli ifadelerle başlar — kütükteki
istek satırını alanlarına ayırmanın, geçersiz satırları elemenin ve zaman damgasını
yeniden biçimlendirmenin ortak dili budur.
