---
title: 'Fonksiyonlar ve Kapsam'
source: 'https://academia.sh/tr/kurslar/kabuk-programlama/fonksiyonlar-ve-kapsam'
course: 'Kabuk Programlama'
language: tr
updated: '2026-08-17T18:10:01+00:00'
license: 'CC BY-SA 4.0'
---

# Fonksiyonlar ve Kapsam

Fonksiyon tanımı, argüman geçişi, çıkış koduyla değer döndürmenin ayrımı, yerel değişkenler ve dinamik kapsam.

Betik büyüdükçe aynı iş birden çok yerde tekrar ediyor: hata bildirme, bölüm başlığı
yazma, bir alanı sayıp sıralama. Programlama Temelleri kursunda bunun karşılığı
fonksiyondu ve fonksiyon, adlandırılmış parametreler alıp bir değer döndüren yapıydı.

Kabuktaki fonksiyon farklı bir şeydir. **Adlandırılmış bir komuttur**: konumsal
parametrelerle çağrılır, çıkış kodu döndürür ve sonucunu — bir değer üretiyorsa —
standart çıktısına yazar. Yani kabuk fonksiyonu, bir programın kabuk içindeki
karşılığıdır.

## Tanım ve Çağrı

```sh
bolum() { printf '\n== %s ==\n' "$*"; }
bolum "En cok istenen yollar"
```

```

== En cok istenen yollar ==
```

Gövde süslü ayraçlar arasındadır. Ayraçlar sözcük olarak tanındığı için çevrelerinde
boşluk zorunludur ve son komuttan sonra `;` ya da satır sonu gerekir. Bash
`function ad { ... }` yazımını da tanır; POSIX olan biçim yukarıdakidir.

Fonksiyon çağrıldığı yerde tanımlı olmalıdır. Kabuk dosyayı yukarıdan aşağı okur;
tanımdan önceki bir çağrı "komut bulunamadı" hatası verir:

```sh
cagir_once
echo "kod=$?"
```

```
./f.sh: line 14: cagir_once: command not found
kod=127
```

Bu yüzden fonksiyonlar betiğin başında, iş yapan kodun üstünde toplanır.

## Argümanlar

Fonksiyon çağrıldığında konumsal parametreler fonksiyonunkilerle değiştirilir: `$1`,
`$2`, `$#`, `"$@"` fonksiyona verilen argümanları gösterir. Bir istisna vardır — `$0`
değişmez, betiğin adını göstermeye devam eder.

```sh
kim() { echo "0=$0 1=$1 sayi=$#"; }
kim a b
```

```
0=./f.sh 1=a sayi=2
```

Argüman aktarımında ikinci dersteki kural geçerlidir: `"$@"` kullanılır, `$*` yalnızca
ileti metni üretmek için yazılır.

Kabuk fonksiyonlarının imzası yoktur; eksik argümanla çağrılan fonksiyon hata vermez,
`$1` boş kalır. Zorunlu argümanlar gövdenin başında sınanmalıdır:

```sh
sinif_adi() {
  [ "$#" -eq 1 ] || { echo "sinif_adi: bir argüman bekler" >&2; return 2; }
  ...
}
```

## Çıkış Kodu Döndürmek

`return` fonksiyonu sonlandırır ve çıkış kodunu belirler. Kod, süreç çıkış kodlarıyla
aynı sözleşmeye tabidir: 0 başarı, sıfırdan farklı başarısızlık, aralık 0–255.

```sh
gecerli_kod() {
  case "$1" in
    [1-5][0-9][0-9]) return 0 ;;
    *)               return 1 ;;
  esac
}
gecerli_kod 404; echo "404 -> $?"
gecerli_kod abc; echo "abc -> $?"
```

```
404 -> 0
abc -> 1
```

Aralık dışı değerler 256'ya göre indirgenir; `return 300` yazan bir fonksiyon `44`
döndürür.

`return` ile `exit` karıştırılmamalıdır. `return` yalnızca fonksiyondan çıkar; `exit`
betiğin tamamını sonlandırır.

```sh
#!/usr/bin/env bash
f() { echo "f icinde"; return 1; }
g() { echo "g icinde"; exit 4; }
f; echo "f sonrasi devam, kod=$?"
g; echo "BU SATIR YAZILMAZ"
```

```
f icinde
f sonrasi devam, kod=1
g icinde
```

```sh
echo $?
```

```
4
```

Kural: kitaplık niteliğindeki fonksiyonlar `return` kullanır ve kararı çağırana bırakır;
yalnızca "ölümcül hata" işlevi gören yardımcılar `exit` çağırır.

## Değer Döndürmek

`return` bir değer döndürme aracı değildir; 0–255 aralığındaki bir kod, dizgi ya da büyük
sayı taşıyamaz. Kabukta değer döndürmenin yolu standart çıktıya yazmak, çağıranın da onu
komut yerine koymayla almasıdır.

```sh
sinif_adi() {
  case "$1" in
    2) echo "basarili"       ;;
    3) echo "yonlendirme"    ;;
    4) echo "istemci hatasi" ;;
    5) echo "sunucu hatasi"  ;;
    *) echo "tanimsiz"; return 1 ;;
  esac
}
ad=$(sinif_adi 4); echo "4 -> $ad"
```

```
4 -> istemci hatasi
```

Bu sözleşmenin doğrudan bir sonucu vardır: **değer döndüren bir fonksiyon, standart
çıktıya başka hiçbir şey yazamaz.** İlerleme iletisi ya da uyarı yazması gerekiyorsa
standart hataya yazar. Bu, konunun ilk dersindeki akış ayrımının pratikte neden gerekli
olduğunun en açık örneğidir.

İkinci sonuç maliyettir: komut yerine koyma bir alt kabuk yaratır. Döngü içinde çok sayıda
çağrı yapan betiklerde bu, ölçülebilir bir yavaşlamaya yol açar. Değeri bir genel
değişkene yazmak alternatiftir; okunurluğu düşürdüğü için ancak gerektiğinde başvurulur.

## Kapsam: Öntanımlı Olarak Genel

Kabukta değişkenler öntanımlı olarak **geneldir**. Fonksiyon içinde yapılan atama, dışarıda
da görünür.

```sh
sayac=0
artir() { sayac=$((sayac + 1)); }
artir; artir; echo "sayac=$sayac"
```

```
sayac=2
```

Bu, Programlama Temelleri kursundaki varsayılanın tersidir; orada fonksiyon gövdesindeki
atama yerel bir ad yaratırdı. Kabuğun davranışı, fonksiyonun bir "komut" olarak
tasarlanmasının sonucudur — komutlar da kabuk değişkenlerini görür.

`local` bildirimi adı fonksiyona bağlar:

```sh
x="disarida"
denemel() { local x="iceride"; echo "fonksiyon icinde: $x"; }
denemel; echo "fonksiyon disinda: $x"
```

```
fonksiyon icinde: iceride
fonksiyon disinda: disarida
```

`local` POSIX kabuk dilinde tanımlı değildir; yaygın kabukların hemen hepsinde bulunur ama
`#!/bin/sh` bildiren bir betikte kullanılması taşınabilirlik güvencesini kaldırır.

Kural: **fonksiyon içinde kullanılan her geçici değişken `local` bildirilir.** Bildirilmeyen
bir ad, çağıran bağlamdaki aynı adlı değişkeni sessizce ezer; bu, uzun betiklerde en zor
bulunan hata sınıfıdır.

## Dinamik Kapsam

`local` bildirilen bir ad, yalnızca tanımlandığı fonksiyona değil, **o fonksiyonun
çağırdığı tüm fonksiyonlara** görünür. Kabuğun kapsam modeli sözcüksel değil
**dinamiktir**.

```sh
ic()  { echo "ic gorur: $gizli"; }
dis() { local gizli="dis fonksiyondan"; ic; }
dis
echo "ana kabuk gorur: [${gizli-tanimsiz}]"
```

```
ic gorur: dis fonksiyondan
ana kabuk gorur: [tanimsiz]
```

`ic` fonksiyonu `gizli` adını hiç tanımlamadığı hâlde gördü, çünkü çağrı zinciri üzerinde
o ad etkindi. Programlama Temelleri kursunda tanıtılan sözcüksel kapsamda bu görünürlük
oluşmazdı; orada bir adın hangi tanıma bağlandığı, kodun yazıldığı yere bakılarak
belirlenirdi.

Pratik sonuç: fonksiyonlarınızın davranışı, kendilerinin görmediği bir çağrıcının yerel
değişkenlerine bağlı hâle gelebilir. Bunu önlemenin yolu, fonksiyonların ihtiyaç duyduğu
her değeri argüman olarak almasıdır.

## `local` ve Çıkış Kodu

`local` bir komuttur ve kendi çıkış kodunu üretir. Bildirimle atamayı aynı satırda
yapmak, sağdaki komutun kodunu görünmez kılar:

```sh
basarisiz() { return 3; }
dene1() { local d; d=$(basarisiz); echo "ayri atama        -> $?"; }
dene2() { local d=$(basarisiz);    echo "local ile birlikte -> $?"; }
dene1; dene2
```

```
ayri atama        -> 3
local ile birlikte -> 0
```

İkinci fonksiyonda görülen `0`, `local` komutunun kendi kodudur. Katı kip altında bu,
başarısız bir komutun betiği durdurmamasına yol açar — Hata Yönetimi dersinde aynı tuzak
yeniden ele alınacak. Kural: **bildirim ile değer atama ayrı satırlara yazılır.**

## Alt Kabuk Gövdeli Fonksiyonlar

Gövde süslü ayraç yerine parantezle yazılırsa fonksiyon bir alt kabukta çalışır. Dizin
değiştirme, `IFS` ayarlama ya da kabuk seçeneği açma gibi yan etkiler çağırana sızmaz:

```sh
gecici() ( cd /tmp && pwd )
```

Bedeli bir süreç yaratma maliyeti ve genel değişken atamalarının kaybolmasıdır. Yalıtım
gerçekten gerekiyorsa doğru araçtır.

## Betiğe Uygulama

`rapor.sh`, tekrar eden işleri fonksiyonlara alır:

```sh
BETIK_ADI="rapor.sh"

hata()  { printf '%s: hata: %s\n'  "$BETIK_ADI" "$*" >&2; }
uyari() { printf '%s: uyari: %s\n' "$BETIK_ADI" "$*" >&2; }
oldur() { hata "$1"; exit "${2:-1}"; }
bolum() { printf '\n== %s ==\n' "$*"; }

sinif_adi() {
  case "$1" in
    2) echo "basarili"       ;;
    3) echo "yonlendirme"    ;;
    4) echo "istemci hatasi" ;;
    5) echo "sunucu hatasi"  ;;
    *) echo "tanimsiz"; return 1 ;;
  esac
}

alan_sayimi() {
  local alan="$1" dosya="$2"
  cut -d' ' -f"$alan" "$dosya" | sort | uniq -c | sort -rn
}
```

Sınamalar tek satıra iner ve hata kodları anlamlarını korur:

```sh
kutuk=erisim.log

[[ "$adet" =~ ^[1-9][0-9]*$ ]] || oldur "-n icin pozitif tam sayi bekleniyor: $adet" 2
[ -f "$kutuk" ] || oldur "duz dosya degil ya da yok: $kutuk" 3
[ -r "$kutuk" ] || oldur "okuma izni yok: $kutuk" 3
[ -s "$kutuk" ] || uyari "kutuk bos: $kutuk"
```

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

```

== Kutuk: erisim.log ==

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

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

```sh
./rapor.sh yok.log; echo "kod=$?"
```

```
rapor.sh: hata: duz dosya degil ya da yok: yok.log
kod=3
```

`oldur` fonksiyonu `exit` çağırdığı için betik orada durur; `hata` ve `uyari` yalnızca
yazar ve kararı çağırana bırakır. Üç fonksiyonun bu biçimde ayrılması, ilerideki
derslerde katı kip eklenirken tek dokunuş noktası sağlayacak.

## Özet

- Kabuk fonksiyonu adlandırılmış bir komuttur: konumsal parametrelerle çağrılır, çıkış
  kodu döndürür, sonucunu standart çıktısına yazar. `$0` fonksiyon içinde değişmez.
- `return` çıkış kodu belirler ve yalnızca fonksiyondan çıkar; `exit` betiği sonlandırır.
- Değer döndürmenin yolu standart çıktıya yazmaktır; bu nedenle değer döndüren fonksiyon
  uyarılarını standart hataya yazmak zorundadır.
- Değişkenler öntanımlı olarak geneldir; `local` bildirimi adı fonksiyona bağlar ve her
  geçici değişken için yazılmalıdır.
- Kabuğun kapsamı dinamiktir: `local` bir ad, çağrılan fonksiyonlara da görünür.
- `local d=$(komut)` yazımı komutun çıkış kodunu gizler; bildirim ile atama ayrılır.

## Sonraki Adım

Rapordaki her sayım, kütüğü baştan sona bir kez daha okuyor. Beş sayım için beş tarama
yapılıyor. Bunu tek taramaya indirmek, ara sonuçları bellekte tutmayı gerektirir. Sonraki
ders dizileri ve ilişkisel dizileri ele alır; ikincisinin hangi bash sürümünden itibaren
bulunduğu ve bulunmadığında ne yapılacağı da orada gösterilecek.
