Metin İşleme: sed, awk ve grep ile Güçlü Entegrasyon

Sistem yöneticiliğinde zamanın büyük bir kısmı log dosyalarını karıştırmak, konfigürasyon dosyalarında değişiklik yapmak ve büyük metin yığınlarından anlamlı bilgi çıkarmaya çalışmakla geçer. İşte tam da bu noktada sed, awk ve grep üçlüsü hayat kurtarıcı oluyor. Bu araçları ayrı ayrı kullanmak bile güçlü, ama birlikte pipeline içinde entegre ettiğinde gerçek sihir başlıyor. Bu yazıda sadece teorik anlatımla kalmayacak, gerçek dünyada karşılaşacağın senaryolar üzerinden bu araçların nasıl birlikte kullanılacağını göstereceğim.

Temeli Sağlamlaştıralım: Her Aracın Rolü

Üçlüyü entegre kullanmadan önce her birinin ne iş yaptığını netleştirmek gerekiyor.

grep bir metin içinde desen arar ve eşleşen satırları döndürür. Filtreleme aracıdır. Hayatın karmaşasından sana lazım olanı seçip ayırır.

sed (stream editor) metin üzerinde dönüşüm yapar. Değiştirme, silme, ekleme gibi operasyonlar için kullanılır. Bir editör gibi düşün ama etkileşimsiz, otomatik çalışan bir editör.

awk ise aslında tam bir programlama dilidir. Sütun bazlı metin işleme, hesaplama, koşullu mantık için kullanılır. Log analizi ve rapor üretiminde awk’ın yerini dolduracak başka bir araç bulmak zordur.

Bu üçünün gücü pipeline (|) operatörüyle birleştiğinde ortaya inanılmaz esnek araçlar çıkıyor.

grep: Temel Filtreleme ve İleri Seviye Kullanım

grep’in en temel kullanımını herkes biliyor ama bazı parametreler gerçekten göz ardı ediliyor.

# Temel kullanım
grep "ERROR" /var/log/syslog

# -i: Büyük/küçük harf duyarsız arama
grep -i "error" /var/log/syslog

# -v: Eşleşmeyenleri göster (ters filtre)
grep -v "DEBUG" /var/log/app.log

# -E: Genişletilmiş regex (egrep ile aynı)
grep -E "ERROR|WARN|CRITICAL" /var/log/app.log

# -c: Eşleşen satır sayısını göster
grep -c "ERROR" /var/log/app.log

# -n: Satır numarasıyla birlikte göster
grep -n "ERROR" /var/log/app.log

# -B ve -A: Eşleşmeden önce/sonra N satır göster
grep -B 2 -A 5 "CRITICAL" /var/log/app.log

# -r: Dizini özyinelemeli tara
grep -r "password" /etc/nginx/

Parametreleri listelemek güzel ama asıl önemli olan hangi durumda ne kullanacağını bilmek. Örneğin bir serviste kritik hata aldığında sadece grep -i "error" yazmak yerine context’i de görmek için -B 3 -A 10 kullanmak seni çok daha hızlı bir yere götürür.

sed: Metin Dönüşümünün Ustası

sed’in en çok kullanılan komutu s (substitute) operatörüdür ama bu aracın çok daha fazlası var.

# Temel değiştirme: ilk eşleşmeyi değiştir
sed 's/eski/yeni/' dosya.txt

# g flag ile tüm eşleşmeleri değiştir
sed 's/eski/yeni/g' dosya.txt

# -i ile dosyayı yerinde düzenle
sed -i 's/http:/https:/g' /etc/app/config.conf

# -i ile yedek al
sed -i.bak 's/http:/https:/g' /etc/app/config.conf

# Belirli satır aralığında değişiklik
sed '10,20s/foo/bar/g' dosya.txt

# Satır silme: boş satırları kaldır
sed '/^$/d' dosya.txt

# Yorum satırlarını kaldır
sed '/^#/d' /etc/nginx/nginx.conf

# Belirli satırı sil (örnek: 5. satırı)
sed '5d' dosya.txt

# İlk ve son satırı sil
sed '1d;$d' dosya.txt

# Satır başına metin ekle
sed 's/^/PREFIX: /' dosya.txt

# Birden fazla sed komutu -e ile
sed -e 's/foo/bar/g' -e 's/baz/qux/g' dosya.txt

Gerçek dünya senaryosu: Nginx konfigürasyonunu production’a taşırken tüm localhost referanslarını production IP’siyle değiştirmen gerekiyor.

# Önce ne değişeceğini test et (dosyayı değiştirme)
sed 's/localhost/192.168.1.100/g' /etc/nginx/sites-available/myapp

# Onayladıktan sonra yerinde değiştir
sed -i.bak 's/localhost/192.168.1.100/g' /etc/nginx/sites-available/myapp

# Değişiklikleri kontrol et
diff /etc/nginx/sites-available/myapp.bak /etc/nginx/sites-available/myapp

awk: Pipeline’ın Beyni

awk’ı sadece print $1 için kullananlar bu aracın kapasitesinin belki yüzde onunu kullanıyordur. awk gerçek anlamda bir programlama dilidir.

# Temel sütun yazdırma
awk '{print $1}' dosya.txt

# Alan ayırıcı belirleme (-F)
awk -F: '{print $1, $3}' /etc/passwd

# Koşullu yazdırma
awk '$3 > 1000 {print $1}' /etc/passwd

# Toplam hesaplama
awk '{sum += $5} END {print "Toplam:", sum}' access.log

# NR ile satır numarası
awk 'NR==5' dosya.txt

# Belirli satır aralığı
awk 'NR>=10 && NR<=20' dosya.txt

# BEGIN ve END blokları
awk 'BEGIN {print "Başlık"} {print $0} END {print "Son"}' dosya.txt

# Birden fazla alan ayırıcısı
awk -F'[,;]' '{print $2}' dosya.csv

Daha ileri seviye bir örnek olarak, Apache access log’undan en çok istek yapan IP’leri bulmak:

awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

Bu tek satır pipeline ile log dosyasındaki IP’leri alıp, sıralayıp, tekrarları sayıp, en çok görünenden aza doğru sıralıyoruz. DDoS tespitinde veya rate limiting kararı alırken bunu çok kullanırsın.

Entegrasyon: Pipeline ile Güç Birleştirme

Asıl konuya geldik. Bu üç aracı birlikte kullanmak, her birini ayrı ayrı kullanmaktan çok daha güçlü sonuçlar veriyor.

Senaryo 1: Log Analizi ve Hata Raporu

Diyelim ki production’da bir servis çöktü ve neden çöktüğünü bulmaya çalışıyorsun.

# Son 1 saatin ERROR loglarını al, timestamp'i temizle,
# sadece hata mesajlarını çek ve say
grep "ERROR" /var/log/app/application.log | 
  grep "$(date '+%Y-%m-%d %H')" | 
  sed 's/.*ERROR: //' | 
  awk '{msg=$0; gsub(/[0-9]+/, "N", msg); print msg}' | 
  sort | uniq -c | sort -rn | head -20

Bu pipeline şunları yapıyor:

  • grep ile ERROR satırlarını filtrele
  • Mevcut saate ait logları seç
  • sed ile timestamp ve log level kısmını kaldır
  • awk ile sayısal değerleri N ile değiştir (benzer hataları gruplayabilmek için)
  • Tekrarları say ve en çok tekrar edenden sırala

Senaryo 2: Konfigürasyon Dosyası Validasyonu

Birden fazla sunucuda nginx konfigürasyonunu kontrol etmek istiyorsun.

# Nginx config'inden aktif server_name'leri çek
grep -v "^#" /etc/nginx/sites-enabled/*.conf | 
  grep "server_name" | 
  sed 's/.*server_names*//' | 
  sed 's/;//' | 
  awk '{for(i=1;i<=NF;i++) print $i}' | 
  sort -u

Bu script yorum satırlarını atlayarak, server_name direktiflerini bulup, fazlalıkları temizleyerek ve her domain adını ayrı satırda listeleyerek sana temiz bir domain listesi veriyor.

Senaryo 3: Kullanıcı ve Süreç Yönetimi

Sistemde belirli bir porta bağlı processleri bul ve sahiplerini listele:

# 80 ve 443 portlarında dinleyen processleri bul
ss -tlnp | 
  grep -E ":80|:443" | 
  awk '{print $NF}' | 
  grep -oP 'pid=K[0-9]+' | 
  while read pid; do
    ps -p "$pid" -o pid,user,cmd --no-headers
  done | 
  awk '{printf "PID: %-8s User: %-15s Cmd: %sn", $1, $2, $3}'

Senaryo 4: CSV ve Yapılandırılmış Veri İşleme

Sistem yöneticileri sık sık CSV formatında envanter veya kullanıcı listeleriyle çalışmak zorunda kalır.

# users.csv dosyasından aktif kullanıcıları filtrele,
# email alanını temizle ve yeni format oluştur
# Format: isim,soyisim,email,durum

grep -v "^#" users.csv | 
  grep ",aktif," | 
  awk -F',' '{
    gsub(/[[:space:]]/, "", $3)
    print $1 " " $2 " <" tolower($3) ">"
  }' | 
  sed 's/  / /g'

Burada awk’ın tolower() fonksiyonunu ve gsub() ile boşluk temizlemeyi bir arada kullandık. Bu tür iş akışları bulk kullanıcı importlarında veya LDAP senkronizasyonlarında çok işe yarıyor.

İleri Seviye Entegrasyon Teknikleri

Çok Adımlı Metin Dönüşümü

Bazen tek bir pipeline yetmez, ara değerleri saklamak gerekir:

#!/bin/bash
# Apache loglarından günlük trafik raporu oluştur

LOG_FILE="/var/log/apache2/access.log"
DATE=$(date '+%d/%b/%Y')
REPORT="/tmp/daily_report_$(date '+%Y%m%d').txt"

echo "Günlük Trafik Raporu - $DATE" > "$REPORT"
echo "=================================" >> "$REPORT"

# Toplam istek sayısı
TOTAL=$(grep "$DATE" "$LOG_FILE" | wc -l)
echo "Toplam İstek: $TOTAL" >> "$REPORT"

# HTTP durum kodu dağılımı
echo -e "nDurum Kodu Dağılımı:" >> "$REPORT"
grep "$DATE" "$LOG_FILE" | 
  awk '{print $9}' | 
  grep -E '^[0-9]{3}$' | 
  sort | uniq -c | sort -rn | 
  awk '{printf "  HTTP %s: %d istekn", $2, $1}' >> "$REPORT"

# En çok istek yapan IP'ler
echo -e "nEn Çok İstek Yapan 10 IP:" >> "$REPORT"
grep "$DATE" "$LOG_FILE" | 
  awk '{print $1}' | 
  sort | uniq -c | sort -rn | head -10 | 
  awk '{printf "  %-15s: %d istekn", $2, $1}' >> "$REPORT"

# En çok ziyaret edilen sayfalar
echo -e "nEn Çok Ziyaret Edilen 10 URL:" >> "$REPORT"
grep "$DATE" "$LOG_FILE" | 
  awk '{print $7}' | 
  grep -v "favicon|robots|.css|.js|.png|.jpg" | 
  sort | uniq -c | sort -rn | head -10 | 
  awk '{printf "  %-50s: %dn", $2, $1}' >> "$REPORT"

cat "$REPORT"

Bu script gerçek bir production ortamında kullanılabilir düzeyde. Crontab’a ekleyip her sabah mail atmasını da sağlayabilirsin.

Regex Gücünü Maksimize Etmek

grep, sed ve awk’ın her biri farklı regex motorları kullanır. Bu farkları bilmek önemli:

# grep POSIX extended regex
grep -E '^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' access.log

# grep Perl-compatible regex (-P) - lookahead/lookbehind için
grep -P '(?<=[)[^]]+(?=])' access.log

# sed regex ile gruplama ve geri referans
# Log satırından sadece IP:PORT formatını çek
echo "Bağlantı 192.168.1.100:8080'e yapıldı" | 
  sed 's/.*([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}:[0-9]+).*/1/'

# awk ile regex eşleşme
awk '/^[0-9]+.[0-9]+.[0-9]+.[0-9]+/ && $9 >= 400 {print $1, $9, $7}' access.log

Dinamik sed ve awk Kullanımı

Shell değişkenlerini bu araçlara aktarmak bazen kafa karıştırıcı olabiliyor:

#!/bin/bash
# Değişken içeren sed ve awk örnekleri

OLD_IP="10.0.0.1"
NEW_IP="10.0.0.50"

# Değişkeni sed'e geçir
sed "s/$OLD_IP/$NEW_IP/g" /etc/hosts

# awk'a değişken geçir (-v ile)
THRESHOLD=1000
awk -v limit="$THRESHOLD" '$5 > limit {print $0}' traffic.log

# Birden fazla awk değişkeni
START_DATE="2024-01-01"
END_DATE="2024-01-31"
awk -v start="$START_DATE" -v end="$END_DATE" 
  '$1 >= start && $1 <= end {print $0}' monthly.log

Pratik Araç Seti: Hazır Pipeline’lar

Günlük işlerinde kopyala-yapıştır kullanabileceğin hazır pipeline koleksiyonu:

# Disk kullanımını analiz et, sadece %80 üzerini göster
df -h | grep -v "Filesystem" | awk '{gsub(/%/,""); if($5+0 > 80) print $0}'

# Aktif network bağlantılarını say ve grupla
ss -tan | grep -v "State" | awk '{print $1}' | sort | uniq -c | sort -rn

# Sistemdeki en büyük 20 dosyayı bul
find / -type f -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null | 
  xargs ls -la 2>/dev/null | 
  sort -k5 -rn | 
  awk '{printf "%10s MB  %sn", int($5/1048576), $NF}' | 
  head -20

# Crontab'daki tüm kullanıcıların joblarını listele
for user in $(cut -f1 -d: /etc/passwd); do
  crontab -u "$user" -l 2>/dev/null | 
    grep -v "^#|^$" | 
    sed "s/^/$user: /"
done

# Failed login girişimlerini analiz et
grep "Failed password" /var/log/auth.log | 
  grep -oP 'from K[0-9.]+' | 
  sort | uniq -c | sort -rn | 
  awk '$1 > 10 {print "DIKKAT - " $1 " basarisiz giris: " $2}'

Performans ve İyi Pratikler

Bu araçları kullanırken dikkat etmen gereken bazı noktalar var:

Pipeline uzunluğu: Her pipe yeni bir process başlatır. Çok uzun pipeline’lar yerine zaman zaman tek bir awk scripti yazmak daha verimli olabilir.

# Verimsiz: çok fazla pipe
cat dosya | grep "ERROR" | sed 's/ERROR//' | awk '{print $1}' | sort | uniq

# Daha verimli: awk ile tek geçiş
awk '/ERROR/ {sub(/ERROR/, ""); seen[$1]++} END {for(k in seen) print k}' dosya

Büyük dosyalar için: Gigabyte boyutundaki log dosyalarında cat ile başlamak yerine direkt dosyayı argüman olarak ver.

# Yavaş
cat /var/log/huge.log | grep "ERROR"

# Hızlı
grep "ERROR" /var/log/huge.log

sed -i kullanımı: Dosyayı yerinde düzenlemeden önce mutlaka yedek al veya test ortamında dene. -i.bak ile yedek almak bir alışkanlık haline gelmeli.

Özel karakterlerden kaçınma: sed ve awk’da /, ., * gibi karakterler regex anlamı taşır. Değişkenlerden gelen bu karakterler sorun çıkarabilir.

# IP adresindeki noktaları escape etmek için
IP="192.168.1.1"
ESCAPED_IP=$(echo "$IP" | sed 's/./\./g')
grep "$ESCAPED_IP" access.log

Hata Ayıklama ve Test

Pipeline’larını debug etmenin en iyi yolu adım adım test etmektir:

# Pipeline'ı adım adım test et
# 1. Adım: grep çıktısını gör
grep "ERROR" app.log | head -5

# 2. Adım: sed ekle ve test et
grep "ERROR" app.log | sed 's/ERROR: //' | head -5

# 3. Adım: awk ekle
grep "ERROR" app.log | sed 's/ERROR: //' | awk '{print $1}' | head -5

# tee ile ara çıktıları dosyaya yaz
grep "ERROR" app.log | tee /tmp/debug1.txt | sed 's/ERROR: //' | tee /tmp/debug2.txt | awk '{print $1}'

tee komutu pipeline’ı bozmadan ara çıktıları kaydetmen için mükemmeldir. Debug sürecini çok kolaylaştırır.

Sonuç

sed, awk ve grep üçlüsü bir sysadmin’in en temel silahlarından. Bu araçları ayrı ayrı öğrenmek güzel bir başlangıç ama gerçek güç onları pipeline içinde entegre ettiğinde ortaya çıkıyor. Bir Apache log dosyasından güvenlik raporu oluşturmak, konfigürasyon dosyalarında toplu değişiklik yapmak veya CSV verilerini dönüştürmek için tek satır komutlar yazabilmek ciddi zaman kazandırıyor.

Bu araçların her birinin farklı güçlü yönleri var: grep hızlı filtreleme için, sed metin dönüşümü için, awk ise hesaplama ve raporlama için ideal. Hangi işi hangi araçla yapacağını öğrenmek ve bunları doğru kombinasyonlarda birleştirmek, seni ortalama bir sysadmin’den gerçekten verimli çalışan birine dönüştürür.

Buradaki örnekleri doğrudan kopyalayıp kullanabilirsin ama daha da önemlisi arkasındaki mantığı kavrayıp kendi senaryolarına uyarlaman. Her production ortamı farklıdır ve bu araçların esnekliği sayesinde hemen hemen her metin işleme ihtiyacını karşılayabilirsin. Regex konusunu derinlemesine öğrenmek de bu araçların verimliliğini katlar, o da ayrı bir yazı konusu.

Yorum yapın