Bash tools
TEKNİK REHBER BASH TOOLS METİN İŞLEME 2026

Unix metin işleme
üçlüsü.

grep filtreler, sed dönüştürür, awk programlar. Üçünü birlikte öğren — hangi durumda hangisine uzanacağını bilmek, her birini tek başına bilmekten daha değerli.

00 Neden üçü birlikte

Üçü farklı soruları yanıtlar — ama aynı pipeline'da yan yana çalışırlar.

Unix metin araçları tek bir şeyi iyi yapar prensibiyle tasarlanmıştır. Bu üç araç da bu felsefeyi somutlaştırır:

  grep  →  satır filtreler     "bunu içeren satırları ver"
  sed   →  satır dönüştürür   "şunu şuna çevir, sil, ekle"
  awk   →  satırı programlar  "alanları parçala, hesapla, raporla"
    

Bir işlemi yapabilmek için tek bir araç yeterli olmayabilir. Ama üçünü zincirlediğinde neredeyse her metin dönüşümünü gerçekleştirebilirsin — Python veya Perl yazmadan.

MENTAl MODEL

grep: regex ile satır seç → sed: seçilen satırı düzenle → awk: satırı alanlarına ayır, hesapla. Üçü birbirine pipe ile bağlanır; her biri bir öncekinin çıktısını alır.

Bu rehberde aynı nginx access log dosyasını üçüyle işleyeceğiz. Böylece hangisinin ne işe yaradığını soyut değil, somut olarak göreceksin.

01 grep — temel kullanım

grep (Global Regular Expression Print) — bir dosyada ya da stdin'de pattern'e uyan satırları döker.

Temel sözdizimi

bash
grep 'pattern' dosya.txt
grep 'pattern' dosya1.txt dosya2.txt
grep 'pattern' *.log

# stdin'den oku
cat access.log | grep '404'

# birden fazla satır üret (grep sonrası awk için klasik):
grep 'ERROR' app.log | grep -v 'timeout'

Sık kullanılan flagler

-i
büyük/küçük harf farkı gözetme (case-insensitive). grep -i 'error' → ERROR, Error, error hepsini yakalar.
-v
eşleşmeyen satırları göster (invert). grep -v 'DEBUG' → DEBUG içermeyen satırlar.
-n
satır numarasını çıktıya ekle. Debug yaparken hangi satırda olduğunu görmek için vazgeçilmez.
-r
dizini özyinelemeli tara. grep -r 'TODO' src/
-R
-r gibi ama symlink'leri de takip eder.
-l
eşleşen satır yerine sadece dosya adını döker. grep -rl 'deprecated' .
-c
eşleşen satır sayısını döker (count). Log analizinde hızlı istatistik için.
-w
tam kelime eşleşmesi (word boundary). grep -w 'log' → "log" bulur ama "logger" bulmaz.
-E
Extended regex kullan (+ ? | () için ters eğik çizgi gerekmez). Alias: egrep.
-F
Fixed string — regex yorumlama yapma, literal ara. Nokta ve parantez içeren arama yaparken hatalı yorumlamayı önler. Alias: fgrep.
-o
sadece eşleşen kısmı döker (tüm satır değil). IP adresi veya URL çekmeye yarar.
-A N
eşleşmeden sonraki N satırı da göster (after context).
-B N
eşleşmeden önceki N satırı da göster (before context).
-C N
eşleşme etrafında N satır bağlam göster (before + after).
--color=auto
eşleşen kısımları renklendirir. Çoğu distro'da alias olarak zaten açık olur.

Pratik örnekler

bash
# 404 olan satırlar, satır numarasıyla
grep -n '404' access.log

# "error" içeren ama "disk" içermeyen log satırları
grep -i 'error' syslog | grep -iv 'disk'

# src/ altında "TODO" geçen tüm dosyaların adı
grep -rl 'TODO' src/

# "WARN" kaç satırda var?
grep -c 'WARN' app.log

# hata satırı ve sonraki 3 satırı göster (stack trace için)
grep -A 3 'Exception' app.log
NE OLUYOR

grep -n '404' access.log — dosyayı satır satır okur, "404" içeren her satırı satır_no:içerik formatında yazar. Geri kalanları siler. Çıktı saf metin, bir sonraki pipe'a hazır.

02 grep — regex derinlemesi

grep iki farklı regex motoru sunar: Basic (BRE) ve Extended (ERE). Fark yalnızca sözdizimsel.

BRE vs ERE

grep (BRE)
+ ? | () {} özel değil — kullanmak için önlerine \ koy: \+ \| \(
grep -E (ERE)
+ ? | () doğrudan özel — literal kullanmak için \ koy: \. \+
grep -P
Perl Compatible Regex — \d \s (?:...) gibi Perl uzantıları. GNU grep'te var ama macOS grep'te yok (homebrew grep gerektirir).

Sık kullanılan meta-karakterler

.
herhangi bir tek karakter (newline hariç).
*
önceki öğenin sıfır veya daha fazla tekrarı.
+
(-E gerekir) bir veya daha fazla tekrar.
?
(-E gerekir) sıfır veya bir tekrar (opsiyonel).
^
satır başı. ^ERROR → "ERROR" ile başlayan satırlar.
$
satır sonu. \.log$ → ".log" ile biten satırlar.
[abc]
karakter sınıfı — a, b veya c.
[^abc]
negated sınıf — a, b, c dışında herhangi biri.
[a-z]
aralık — a'dan z'ye küçük harf.
|
(-E gerekir) alternatif. cat|dog → cat veya dog.
()
(-E gerekir) gruplama. (ha)+ → ha, haha, hahaha…
{n,m}
tekrar sayısı. [0-9]{3,5} → 3 ile 5 basamak arası.

Örnekler

bash
# IPv4 adresi yakala (kaba, ama işe yarar)
grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' access.log

# 4xx veya 5xx HTTP kodları
grep -E ' (4|5)[0-9]{2} ' access.log

# boş olmayan satırlar
grep -v '^$' dosya.txt

# "func" ile başlayan satır (Go kaynak kodu)
grep -rn '^func ' --include='*.go' .

# "error" veya "warn" geçen satırlar (büyük/küçük harf fark etmez)
grep -iE 'error|warn' syslog
DİKKAT — nokta tuzağı

grep '1.2.3.4' yazdığında nokta "herhangi karakter" anlamına gelir: "1X2Y3Z4" de eşleşir. IP aramalarında \. veya -F '1.2.3.4' kullan.

İPUCU — --include ile dosya filtresi

grep -rn 'pattern' --include='*.py' . — sadece .py dosyalarında ara. --exclude='*.min.js' ile belirli dosyaları dışarıda bırak.

03 sed — s/// ikamesi ve address'ler

sed (Stream EDitor) satırları dönüştürür. Kayıttan okuduğu her satıra bir veya daha fazla komut uygular, sonucu yazar.

s/// — ikame komutu

bash
# s/pattern/değiştirme/flags
sed 's/foo/bar/' dosya.txt        # her satırda ilk foo'yu bar yap
sed 's/foo/bar/g' dosya.txt       # her satırda TÜM foo'ları bar yap
sed 's/foo/bar/2' dosya.txt       # her satırda sadece 2. foo'yu değiştir
sed 's/foo/bar/gi' dosya.txt      # global + case-insensitive
sed 's/foo/bar/gp' dosya.txt      # değişen satırı bir de ekstra yaz (p)
g (global)
satırdaki tüm eşleşmeleri değiştir (varsayılan sadece ilki).
i (case-insensitive)
GNU sed'e özgü. macOS sed'de çalışmaz — I kullan ya da homebrew gsed kur.
p (print)
değişen satırı tekrar yazar. Genelde -n ile birlikte — "sadece değişen satırları göster".
N (Nth occurrence)
2, 3, … gibi sayı: sadece o sıradaki eşleşmeyi değiştir.

Address — hangi satıra uygulanacak

sed komutları varsayılan olarak her satıra uygulanır. Önüne bir address yazarsın, yalnızca o satır(lar)a uygulanır.

bash
# Satır numarasıyla address
sed '1s/foo/bar/' dosya.txt          # sadece 1. satırda
sed '2,5s/foo/bar/g' dosya.txt       # 2. ile 5. satır arası
sed '$s/foo/bar/' dosya.txt          # son satırda

# Pattern address
sed '/^#/s/old/new/g' dosya.txt      # # ile başlayan satırlarda
sed '/^#/!s/old/new/g' dosya.txt     # # ile BAŞLAMAYAN satırlarda (! = negation)

# Aralık (pattern'den pattern'e)
sed '/START/,/END/s/foo/bar/g' d.txt  # START'tan END'e kadar
sed '3,/END/s/foo/bar/g' d.txt        # 3. satırdan END pattern'ine kadar
NE OLUYOR

/^#/!s/old/new/g! işareti address'i negete eder: "# ile başlamayan her satırda s komutunu çalıştır". Yorum satırlarını atlayarak kodu düzenlemenin klasik yolu.

Sınırlayıcı değiştirme

Pattern veya replacement içinde / varsa, farklı bir sınırlayıcı kullanabilirsin — sed her karakteri kabul eder:

bash
# /path içeren şeyi değiştirmek zor (\/ yazmak yerine | kullan)
sed 's|/usr/local/bin|/opt/bin|g' script.sh

# # ile de olur
sed 's#http://old.com#https://new.com#g' config.txt

04 sed — inplace düzenleme ve diğer komutlar

sed varsayılan olarak sadece stdout'a yazar, orijinal dosyaya dokunmaz. -i ile yerinde değiştirebilirsin.

-i ile inplace

bash
# GNU sed (Linux): -i, ek uzantı gerekmez
sed -i 's/foo/bar/g' dosya.txt

# macOS sed: -i için boş string uzantısı gerekir
sed -i '' 's/foo/bar/g' dosya.txt

# Yedek al (GNU ve macOS'ta farklı)
sed -i.bak 's/foo/bar/g' dosya.txt  # dosya.txt.bak yedek oluşturur
GNU vs macOS farkı

macOS, BSD sed kullanır. GNU sed, birçok yerde farklı davranır (-i sözdizimi, -E vs -r extended regex bayrağı, \w desteği). macOS'ta güvenilir olmak için brew install gnu-sed ve gsed kullan ya da her farkı bilerek yaz.

d — satır silme

bash
# # ile başlayan satırları sil (yorum satırları)
sed '/^#/d' config.txt

# Boş satırları sil
sed '/^[[:space:]]*$/d' dosya.txt

# 1-5. satırları sil
sed '1,5d' dosya.txt

# Son satırı sil
sed '$d' dosya.txt

p — satır yazdırma, -n ile birlikte

bash
# Sadece "ERROR" içeren satırları yazdır (grep gibi ama sed ile)
sed -n '/ERROR/p' app.log

# 10-20. satırları çıkar (head + tail yerine)
sed -n '10,20p' büyük_dosya.txt

a, i — satır ekleme

bash
# [HOST] satırından SONRA yeni satır ekle
sed '/\[HOST\]/a\  server = 192.168.1.1' config.ini

# [HOST] satırından ÖNCE satır ekle
sed '/\[HOST\]/i\# Auto-generated' config.ini

# Birden fazla komut: -e veya ; ile zincirle
sed -e 's/foo/bar/g' -e '/^$/d' dosya.txt
İPUCU — çok komutlu sed

Birden fazla sed komutu çalıştırmanın iki yolu: -e 'komut1' -e 'komut2' veya 'komut1; komut2'. Daha karmaşık senaryolar için script dosyası: sed -f komutlar.sed dosya.txt.

05 awk — alan modeli ve temel kullanım

awk her satırı alanlara böler ve onlara isimle erişir. "Sütunlarla iş yap" denilince ilk akla gelen araç.

Temel çalışma prensibi

  Her satır için:
    1. Satırı FS (field separator) ile alanlara böl  →  $1  $2  $3 … $NF
    2. pattern { action } kurallarını sırayla değerlendir
    3. Eşleşen action'ları çalıştır
    4. Sonraki satıra geç
    
$0
satırın tamamı.
$1, $2, $N
1., 2., N. alan.
$NF
son alan (NF = Number of Fields).
NR
Number of Records — işlenen toplam satır sayısı (geçerli satır numarası).
NF
Number of Fields — geçerli satırdaki alan sayısı.
FS
Field Separator — varsayılan boşluk/tab. Değiştirmek için -F',' veya BEGIN{FS=","}.
OFS
Output Field Separator — yazdırırken alanlar arasına koyulacak karakter. Varsayılan boşluk.
FILENAME
işlenen dosyanın adı.

-F ile sınırlayıcı belirt

bash
# /etc/passwd dosyasından kullanıcı adı ve shell (: sınırlayıcı)
awk -F: '{print $1, $7}' /etc/passwd

# CSV: alan 2 ve 4'ü al
awk -F, '{print $2, $4}' veri.csv

# Bir karakterden uzun sınırlayıcı → regex kullan
awk -F '  ' '{print $1}'   # çift boşluk
awk -F '[,;]' '{print $1}'  # virgül veya noktalı virgül

print vs printf

bash
# print — otomatik newline ekler, OFS ile alanları ayırır
awk '{print $1, $2}' dosya.txt     # aralarında boşluk
awk '{print $1 ":" $2}' dosya.txt  # birleştirilmiş string

# printf — C benzeri format kontrolü
awk '{printf "%-20s %5d\n", $1, $3}' dosya.txt
#          └── 20 karakter soldan     └── 5 karakter sağdan

# İlk 10 satırı al (head ile aynı)
awk 'NR <= 10' dosya.txt

# Son satırı al (tail -1 ile aynı)
awk 'END{print}' dosya.txt
NE OLUYOR

awk -F: '{print $1, $7}' /etc/passwd — her satırı : ile böler, 1. alanı (kullanıcı adı) ve 7. alanı (shell) aralarında boşlukla yazar. root, daemon, kullanıcı adlarının yanında hangi shell'i kullandıklarını tek komutta görürsün.

06 awk — pattern/action, BEGIN/END

awk'un gerçek gücü: koşullu işlem, toplama, ortalama — tek geçişte, dış araç olmadan.

pattern { action } yapısı

bash
# Pattern bir regex: /ERROR/ içeren satırlar
awk '/ERROR/ {print NR, $0}' app.log

# Pattern bir koşul: 3. alan 100'den büyük
awk '$3 > 100 {print $1, $3}' veri.txt

# Pattern yok → tüm satırlara uygula
awk '{toplam += $3} END{print toplam}' veri.txt

# Action yok → eşleşen satırı olduğu gibi yaz (grep gibi)
awk '/^[0-9]/' dosya.txt

BEGIN ve END

BEGIN { ... }
İlk dosya okunmadan önce çalışır. Başlık yazdırma, FS/OFS atama, sayaç sıfırlama için.
END { ... }
Son satır işlendikten sonra çalışır. Toplam, ortalama, özet yazdırma için.
bash
# Başlık + içerik + toplam
awk '
BEGIN {
    FS = ","
    print "KULLANICI", "TUTAR"
}
NR > 1 {          # başlık satırını atla
    toplam += $3
    print $1, $3
}
END {
    print "---"
    print "TOPLAM:", toplam
}
' satislar.csv

Sayaç ve koşul

bash
# "ERROR" ve "WARN" sayısı
awk '/ERROR/{err++} /WARN/{warn++} END{print "ERROR:", err, "WARN:", warn}' app.log

# Her benzersiz HTTP status kodunun sayısı
awk '{sayac[$9]++} END{for(kod in sayac) print kod, sayac[kod]}' access.log

# Ortalama yanıt süresi (access.log'un son alanı byte, 7. alan status)
awk '{toplam+=$NF; n++} END{printf "Ort: %.2f\n", toplam/n}' access.log
NE OLUYOR

sayac[$9]++ — awk'ta diziler (array) string anahtarlı hash map gibi çalışır, önceden tanımlamana gerek yok. $9 HTTP status kodu için kullanılıyor; her farklı kod için ayrı sayaç tutar. END'de for(anahtar in dizi) ile tüm anahtarları dolaşır.

07 Üçü birlikte — nginx log örneği

Gerçek bir nginx access.log üzerinden grep + sed + awk'u pipeline'da birleştireceğiz.

Örnek log formatı

nginx access.log
192.168.1.10 - alice [10/Apr/2026:09:12:33 +0300] "GET /api/users HTTP/1.1" 200 1423 "-" "curl/7.68.0"
10.0.0.5 - bob [10/Apr/2026:09:13:01 +0300] "POST /api/login HTTP/1.1" 401 87 "-" "Mozilla/5.0"
192.168.1.10 - alice [10/Apr/2026:09:13:45 +0300] "GET /api/users/42 HTTP/1.1" 200 891 "-" "curl/7.68.0"
172.16.0.2 - - [10/Apr/2026:09:14:02 +0300] "GET /nonexistent HTTP/1.1" 404 153 "-" "Python/3.9"
10.0.0.5 - bob [10/Apr/2026:09:14:30 +0300] "POST /api/login HTTP/1.1" 200 312 "-" "Mozilla/5.0"

Senaryo 1: Tüm hata yanıtlarını bul

bash
# 4xx veya 5xx satırları + satır numarası
grep -nE '" (4|5)[0-9]{2} ' access.log

Senaryo 2: IP → status kodu tablosu

bash
# awk ile IP ($1) ve status ($9) çek, status'a göre sırala
awk '{print $1, $9}' access.log | sort -k2 -n

Çıktı:
192.168.1.10 200
192.168.1.10 200
10.0.0.5 200
10.0.0.5 401
172.16.0.2 404

Senaryo 3: Her IP'nin kaç istek gönderdiği

bash
awk '{say[$1]++} END{for(ip in say) print say[ip], ip}' access.log | sort -rn

Çıktı:
2 192.168.1.10
2 10.0.0.5
1 172.16.0.2

Senaryo 4: Sadece GET isteklerini filtrele, URL'yi temizle

bash
# grep ile GET filtrele, awk ile URL al, sed ile query string temizle
grep '"GET ' access.log \
  | awk '{print $7}' \
  | sed 's/?.*//' \
  | sort | uniq -c | sort -rn

Açıklama:
  grep    → sadece GET satırlarını al
  awk $7  → 7. alan = URL ("/api/users")
  sed     → ?query=string kısmını sil
  sort|uniq -c|sort -rn → en çok istek alan URL'ler
NEDEN BU ÜÇLÜ

grep ile ham satır sayısını düşürdün. awk ile yapısal bilgiyi çıkardın. sed ile format temizledi. Her biri kendi işini yaptı, bir sonrakine temiz veri verdi. Bu, Unix felsefesinin özü.

08 Özet — ne zaman hangisi

Doğru aracı seçmek, doğru kullanmak kadar önemlidir.

Araç Ne için ideal Sınırı
grep Satır filtrele, var mı yok mu bak, dosya adı bul, bağlam göster Alan bazlı işlem yapamaz, dönüştüremez, hesaplayamaz
sed Metin ikamesi, satır ekleme/silme, inplace dosya düzenleme Alan hesaplamak, toplamak, karma veri işlemek güçleşir
awk Yapısal metin: alanları parçala, say, topla, raporla, koşullu işle Karmaşık iş mantığı için Python daha anlaşılır olabilir

Hatırlanacaklar

  • grep -E extended regex, grep -F literal, grep -o sadece eşleşen kısım
  • grep -r --include='*.py' — dosya tipi filtreli özyinelemeli arama
  • sed 's/a/b/g' global, 's|/old/path|/new|g' / içeriyorsa sınırlayıcı değiştir
  • sed -i Linux'ta direkt, macOS'ta -i '' gerekir
  • awk -F, '{print $2}' — alan sınırlayıcı ve alan erişimi
  • awk 'END{print toplam}' — BEGIN/END ile öncesi/sonrası mantığı
  • Üçlüyü pipeline'da zincirle: grep | awk | sed | sort | uniq

Bir sonraki adım: find rehberi — dosya sistemi sorguları, -exec, xargs ve prune.

Aynı pipeline araçları için: Unix felsefesi: pipe, tee, xargs.