awk Rehberi: Alanlar ile Veri İşleme

Linux dünyasında metin işlemenin olmazsa olmazlarından biri olan awk, özellikle log analizi, rapor oluşturma ve veri dönüştürme konularında sistem yöneticilerinin en güçlü silahlarından biridir. Ancak birçok sysadmin awk‘ı ya hiç kullanmaz ya da sadece yüzeysel komutlarla geçiştirir. Bu yazıda awk‘ın belki de en temel konseptine, yani alanlara (fields) odaklanacağız ve gerçek dünya senaryolarıyla bu kavramı derinlemesine ele alacağız.

awk Nedir ve Neden Önemlidir?

awk aslında bir programlama dilidir. Alfred Aho, Peter Weinberger ve Brian Kernighan tarafından 1977 yılında geliştirilmiştir ve isimleri bu üç kişinin soyadının baş harflerinden oluşur. Satır satır metin okuyarak her satırda belirttiğiniz işlemleri uygular.

awk‘ın temel çalışma mantığı şu şekildedir: Her satırı okur, bu satırı belirli bir ayraç karakterine göre alanlara böler ve siz bu alanlara erişerek istediğiniz işlemleri yaparsınız. Bu kadar basit ama bu kadar güçlü.

Bir Linux/Windows ortamında awk‘ı öğrenmek neden bu kadar kritik? Çünkü her gün karşılaştığınız log dosyaları, konfigürasyon çıktıları, network trafiği analizleri, kullanıcı raporları hepsi düzenli yapılandırılmış metin verileridir. awk bu verileri cerrahi bir hassasiyetle kesip biçmenizi sağlar.

Alanlara Giriş: $1, $2, $NF

awk bir satırı okuduğunda, bu satırı boşluk veya tab karakterlerine göre parçalara böler. Bu parçaların her birine alan (field) denir.

  • $0: Tüm satırı temsil eder
  • $1: Birinci alanı temsil eder
  • $2: İkinci alanı temsil eder
  • $NF: Son alanı temsil eder (NF = Number of Fields)
  • $(NF-1): Sondan ikinci alanı temsil eder

Basit bir örnekle başlayalım. Diyelim ki /etc/passwd dosyasından kullanıcı adlarını almak istiyoruz:

awk -F: '{print $1}' /etc/passwd

Burada -F: parametresi alan ayracının : karakteri olduğunu belirtir. {print $1} ise her satırın ilk alanını, yani kullanıcı adını ekrana basar.

Şimdi daha karmaşık bir senaryo. Sistemdeki kullanıcıların kabuk (shell) bilgilerini de görmek istiyoruz:

awk -F: '{print $1, $7}' /etc/passwd

Bu komut kullanıcı adını ve kullandığı shell’i yan yana basar. Çıktı şu şekilde görünür:

root /bin/bash
daemon /usr/sbin/nologin
www-data /usr/sbin/nologin

Alan Ayracı (Field Separator) Kullanımı

awk‘ta alan ayracını iki şekilde belirtebilirsiniz:

-F parametresi ile:

awk -F',' '{print $2}' veriler.csv

BEGIN bloğu içinde FS değişkeni ile:

awk 'BEGIN{FS=","} {print $2}' veriler.csv

Her iki yöntem de aynı sonucu verir. Ancak BEGIN bloğu kullanmak, birden fazla ayraç veya karmaşık regex ayraçları için daha esnektir.

Peki ya birden fazla karakter ayraç olarak kullanmak istiyorsanız? Bunu regex ile halledebilirsiniz:

# Hem virgül hem noktalı virgül ayraç olarak kullanalım
awk -F'[,;]' '{print $1, $3}' karisik_veri.txt

Bu yaklaşım özellikle temizlenmemiş veri dosyalarıyla çalışırken hayat kurtarır.

Gerçek Dünya Senaryosu 1: Apache Log Analizi

Bir web sunucusunu yönetiyorsunuz ve Apache access log’unu analiz etmeniz gerekiyor. Log formatı şu şekilde:

192.168.1.100 - frank [10/Oct/2023:13:55:36 -0700] "GET /index.html HTTP/1.1" 200 2326

En fazla istek yapan IP adreslerini bulmak için:

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

Bu komut zinciri şunları yapar: awk ile IP adreslerini çeker, sort ile sıralar, uniq -c ile tekrar sayısını hesaplar, tekrar sort -rn ile büyükten küçüğe sıralar ve head -20 ile ilk 20 sonucu gösterir.

Sadece 404 hatalarını veren istekleri bulmak istiyorsanız:

awk '$9 == 404 {print $1, $7}' /var/log/apache2/access.log

Burada $9 HTTP durum kodunu, $7 ise istenen URL’yi temsil eder. Bu koşullu filtreleme awk‘ın en güçlü özelliklerinden biridir.

OFS: Çıktı Alan Ayracı

Giriş ayracını öğrendik, peki ya çıktı ayracı? awk varsayılan olarak alanları boşlukla ayırarak basar. Bunu değiştirmek için OFS (Output Field Separator) değişkenini kullanırız.

# /etc/passwd'den CSV formatında rapor oluştur
awk -F: 'BEGIN{OFS=","} {print $1,$3,$4,$7}' /etc/passwd

Bu komutun çıktısı şu şekilde olacak:

root,0,0,/bin/bash
daemon,1,1,/usr/sbin/nologin

Bu özellik, farklı formatlardaki verileri dönüştürmek için inanılmaz derecede kullanışlıdır. Örneğin bir sistem raporunu spreadsheet’e aktarmak için CSV’ye dönüştürebilirsiniz.

Alan Sayısını Kullanmak: NF Değişkeni

NF değişkeni her satırdaki alan sayısını tutar. Bu değişkeni hem kontrol hem de son alana erişmek için kullanabilirsiniz.

# Boş olmayan satırları, yani en az bir alanı olanları göster
awk 'NF > 0' dosya.txt

# Her satırdaki alan sayısını göster
awk '{print NF, $0}' dosya.txt

# Son iki alanı göster
awk '{print $(NF-1), $NF}' dosya.txt

Gerçek bir senaryo düşünelim. Bir konfigürasyon dosyasını parse ediyorsunuz ve bazı satırlar yorum satırı ya da boş:

# # ile başlayan ve boş satırları atlayarak sadece geçerli config satırlarını çek
awk 'NF > 0 && $1 !~ /^#/ {print $1, $2}' /etc/ssh/sshd_config

Gerçek Dünya Senaryosu 2: Disk Kullanım Raporu

Sisteminizdeki disk kullanımını izliyorsunuz ve df -h çıktısını işlemeniz gerekiyor:

df -h | awk 'NR > 1 && $5+0 > 80 {print "UYARI: " $6 " - Kullanim: " $5}'

Bu komut NR > 1 ile başlık satırını atlar, $5+0 > 80 ile kullanım yüzdesini kontrol eder (string’i sayıya çevirmek için +0 kullandık) ve 80% üzerindeki bölümleri uyarı mesajıyla gösterir.

Daha kapsamlı bir disk raporu için:

df -h | awk 'NR==1 {print "=== DISK KULLANIM RAPORU ==="} 
             NR > 1 {
               gsub(/%/, "", $5)
               if ($5+0 >= 90) durum="KRITIK"
               else if ($5+0 >= 80) durum="UYARI"  
               else durum="NORMAL"
               print $6 ": " $5"% [" durum "]"
             }'

Alan Değerlerini Değiştirmek

awk sadece alan okumakla kalmaz, bu alanları değiştirmenize de izin verir:

# /etc/passwd'de shell'i bash olmayanları bul ve çıktıyı düzenle
awk -F: 'BEGIN{OFS=":"} $7 != "/bin/bash" {$7="/bin/sh"; print}' /etc/passwd

Bu örnekte $7 alanını değiştirdikten sonra print ile tüm satırı (yeni değeriyle birlikte) basıyoruz. OFS=":" sayesinde çıktı da : ile ayrılmış olacak.

Başka bir senaryo, log dosyasındaki IP adreslerini maskelemek:

awk '{
  split($1, ip, ".")
  ip[4] = "xxx"
  $1 = ip[1]"."ip[2]"."ip[3]"."ip[4]
  print
}' /var/log/apache2/access.log

Gerçek Dünya Senaryosu 3: Ağ Bağlantı Analizi

Sunucunuzdaki aktif bağlantıları analiz etmek istiyorsunuz. ss -tn veya netstat -tn çıktısını işleyelim:

ss -tn | awk 'NR > 1 {
  split($5, addr, ":")
  remote_ip = addr[1]
  count[remote_ip]++
} 
END {
  print "=== BAGLANTI SAYILARI ==="
  for (ip in count) {
    if (count[ip] > 5)
      print ip ": " count[ip] " baglanti"
  }
}'

Bu script her uzak IP’den kaç bağlantı geldiğini sayar ve 5’ten fazla bağlantısı olanları listeler. Potansiyel DDoS veya kötü niyetli tarama aktivitelerini tespit etmek için kullanışlıdır.

BEGIN ve END Blokları ile Alan İşleme

BEGIN bloğu dosya okunmadan önce, END bloğu ise tüm satırlar işlendikten sonra çalışır. Bu blokları alan işlemeyle birleştirince güçlü raporlar oluşturabilirsiniz.

# Bir servis logundaki toplam trafik hesabı
awk 'BEGIN {
    print "Analiz basliyor..."
    toplam = 0
}
{
    toplam += $10  # byte cinsinden transfer edilen veri
    satir++
}
END {
    print "Toplam satir: " satir
    print "Toplam transfer: " toplam/1024/1024 " MB"
    print "Ortalama transfer: " toplam/satir " byte"
}' /var/log/apache2/access.log

Çok Karakterli Alan Ayracı

Bazen alan ayracı tek bir karakter değil, birden fazla karakterden oluşan bir string olabilir. Örneğin bazı log formatlarında || veya :: gibi ayraçlar kullanılır:

# :: ile ayrılmış özel log formatı
awk -F'::' '{print $1, $3}' ozel_log.txt

# Tab karakteri ile ayrılmış dosya
awk -F't' '{print $2, $4}' sekme_ayracli.tsv

# Birden fazla boşluk karakterini tek ayraç olarak kullan
awk -F' +' '{print $1, $3}' bosluklu_dosya.txt

Koşullu Alan İşleme

awk‘ın gerçek gücü koşullu mantıkla birleştiğinde ortaya çıkar:

# Sadece belirli bir alanda pattern eşleşen satırları işle
awk '$4 ~ /ERROR/ {print NR": "$0}' sistem.log

# Sayısal karşılaştırma
awk '$3 > 1000 && $3 < 5000 {print $1, $2, $3}' rapor.txt

# Birden fazla koşul
awk '$1 == "CRITICAL" || $1 == "ERROR" {
    print strftime("%Y-%m-%d %H:%M:%S"), $0
}' uygulama.log

Gerçek Dünya Senaryosu 4: Kullanıcı Hesap Raporu

Sistem yöneticisi olarak periyodik kullanıcı raporları hazırlamak zorunda olabilirsiniz. /etc/passwd dosyasından anlamlı bir rapor çıkaralım:

awk -F: 'BEGIN {
    OFS="t"
    print "KULLANICItUIDtGIDtHOMEtSHELL"
    print "-------t---t---t----t-----"
}
$3 >= 1000 && $3 != 65534 {
    print $1, $3, $4, $6, $7
}
END {
    print "nToplam normal kullanici sayisi: " NR-2
}' /etc/passwd

Bu script sistem kullanıcılarını (UID < 1000) atlayarak sadece gerçek kullanıcıları listeler ve başlık satırı ekler.

Alan İşlemede Yaygın Hatalar ve Çözümleri

Sayısal karşılaştırma hataları: awk string ve sayı karşılaştırmalarında bazen beklenmedik davranabilir.

# Yanlis - string karsilastirmasi yapar
awk '$3 > "100"' dosya.txt

# Dogru - sayisal karsilastirma
awk '$3+0 > 100' dosya.txt
# veya
awk 'int($3) > 100' dosya.txt

Boşluk içeren alanlara erişim: Eğer bir alanda boşluk varsa ve bu alanı tırnak içinde çekmek istiyorsanız, önce ayracı doğru belirlemeniz gerekir.

# Tırnak içindeki değerleri de ayrac olarak kullanmak
awk -F'"' '{print $2}' tirnak_icinde.txt

Satır sonu karakterleri: Windows’tan gelen dosyalarda rn satır sonu olabilir ve bu alanları bozabilir.

# Satir sonu karakterlerini temizle
awk '{gsub(/r/, ""); print $NF}' windows_dosyasi.txt

Pratik İpuçları ve Kısayollar

awk scriptlerini daha okunaklı yazmak için birkaç öneri:

  • Uzun scriptleri -f parametresiyle dosyadan okuyun: awk -f script.awk veri.txt
  • Değişken tanımlamayı -v parametresiyle yapın: awk -v esik=80 '$5+0 > esik {print}' dosya.txt
  • print yerine printf kullanarak formatlanmış çıktı alın
# printf ile duzgun hizalanmis rapor
awk -F: '$3 >= 1000 {printf "%-15s %-5s %-30sn", $1, $3, $6}' /etc/passwd

Birden fazla dosyayı aynı anda işlerken hangi dosyanın işlendiğini FILENAME değişkeniyle takip edebilirsiniz:

awk 'FNR == 1 {print "=== " FILENAME " ==="} {print $1}' *.log

Burada FNR her dosya için sıfırlanan satır numarasıdır, NR ise tüm dosyalar boyunca artan toplam satır numarasıdır.

Sonuç

awk‘ın alan sistemi, metin işlemenin temel taşını oluşturur. $1‘den $NF‘e kadar olan alan notasyonunu, FS ve OFS değişkenlerini, koşullu alan işlemeyi ve gerçek senaryolardaki uygulamalarını gördük.

Bir sysadmin olarak awk‘ı iyi bilmek, günlük iş yükünüzü ciddi ölçüde azaltır. Log analizi, rapor oluşturma, konfigürasyon dosyası parse etme, ağ trafiği analizi gibi onlarca görevi birkaç satır awk kodu ile halledebilirsiniz.

Pratik yapmak için önerim şu: Hemen şu an çalıştığınız sunucuya gidin, df -h, ss -tn veya /var/log/syslog gibi bir çıktı alın ve bu yazıdaki teknikleri uygulayın. awk‘ı öğrenmenin en iyi yolu onu gerçek verilerle, gerçek problemleri çözerek kullanmaktır.

Bir sonraki yazıda awk‘ta döngüler, diziler ve daha gelişmiş programlama yapılarını ele alacağız. O zamana kadar terminal açık, awk hazır!

Yorum yapın