awk ile Metin Tabanlı Fatura ve Zaman Çizelgesi Verilerinden Özet Rapor Üretme
Yıllar önce bir muhasebe departmanının bana “bu Excel dosyalarını birleştir, özet çıkar” diye yığdığı günleri çok iyi hatırlıyorum. O gün awk ile tanışmam tam anlamıyla bir aydınlanma oldu. Şimdi fatura verileri, zaman çizelgeleri, log dosyaları… hepsini terminal üzerinden birkaç satırda işleyebiliyorum. Eğer siz de her ay muhasebe veya proje yönetim ekibine rapor hazırlamak zorundaysanız, bu yazı tam size göre.
Neden awk?
awk sadece bir metin işleme aracı değil, aslında küçük ama güçlü bir programlama dilidir. Satır satır veri işleyebilir, alanları ayrıştırabilir, toplama-ortalama gibi hesaplamalar yapabilir ve son derece esnek çıktılar üretebilir. Python veya Perl ile de yapılabilir elbette, ama awk ile terminal üzerinde tek satırda çözebileceğiniz şeyleri neden onlarla uğraşasınız?
Tipik kullanım senaryoları şunlar:
- CSV veya TSV formatındaki fatura verilerinden departman bazlı özet üretmek
- Çalışan zaman çizelgelerinden toplam saat ve maliyet hesaplamak
- Birden fazla dosyayı birleştirip konsolide rapor çıkarmak
- Belirli eşik değerleri aşan faturaları filtrelemek
Temel awk Sözdizimi Hatırlatması
Bazı okuyucularımız awk‘ı ilk kez görüyor olabilir, o yüzden hızlıca hatırlatalım:
awk 'KURAL { EYLEM }' dosya.txt
- FS: Alan ayırıcısı (Field Separator), varsayılan boşluk
- NR: O ana kadar işlenen toplam satır sayısı
- NF: Mevcut satırdaki alan sayısı
- $1, $2, …: Sırasıyla 1., 2., … alan değerleri
- $0: Tüm satır
- BEGIN: Dosya işlenmeden önce çalışır
- END: Dosya işlendikten sonra çalışır
Örnek Veri Setlerimiz
Gerçek dünya senaryolarına geçmeden önce çalışacağımız veri formatlarını tanımlayalım. Pratikte şirketlerde karşılaşacağınız formatlara mümkün olduğunca yakın tuttum.
faturalar.csv dosyamız şöyle görünüyor:
FaturaNo,Tarih,Musteri,Departman,Tutar,KDV,Durum
INV-001,2024-01-05,ABC Ltd,IT,15000,2700,Odendi
INV-002,2024-01-12,XYZ AS,Pazarlama,8500,1530,Beklemede
INV-003,2024-01-18,DEF Koop,IT,22000,3960,Odendi
INV-004,2024-02-03,ABC Ltd,HR,5000,900,Iptal
INV-005,2024-02-14,GHI San,Pazarlama,12000,2160,Odendi
INV-006,2024-02-22,XYZ AS,IT,9500,1710,Beklemede
INV-007,2024-03-08,JKL Tic,HR,7800,1404,Odendi
zamancizelgesi.csv dosyamız:
CalisanID,Ad,Departman,Tarih,GirisSaati,CikisSaati,CalismaSaati,SaatlikUcret
E001,Ahmet Yilmaz,IT,2024-01-08,09:00,18:00,9,150
E002,Fatma Kaya,Pazarlama,2024-01-08,08:30,17:30,9,120
E001,Ahmet Yilmaz,IT,2024-01-09,09:00,19:00,10,150
E003,Mehmet Demir,IT,2024-01-09,10:00,18:00,8,180
E002,Fatma Kaya,Pazarlama,2024-01-10,08:30,18:30,10,120
E004,Ayse Celik,HR,2024-01-10,09:00,17:00,8,100
Fatura Verilerinden Departman Bazlı Özet
İlk ve en sık ihtiyaç duyduğum senaryo: her departmanın toplam fatura tutarını görmek. Basit ama hayat kurtarıcı.
awk -F',' 'NR>1 && $8=="Odendi" {
dept[$4] += $5
kdv[$4] += $6
count[$4]++
}
END {
printf "%-15s %12s %10s %8sn", "Departman", "Toplam Tutar", "Toplam KDV", "Fatura"
printf "%-15s %12s %10s %8sn", "---------------", "------------", "----------", "------"
for (d in dept) {
printf "%-15s %12.2f %10.2f %8dn", d, dept[d], kdv[d], count[d]
}
}' faturalar.csv
Burada NR>1 ile başlık satırını atlıyoruz, $8=="Odendi" ile sadece ödenmiş faturaları filtreliyoruz. Sonuç olarak departman bazında toplam tutar, KDV ve fatura sayısı görüyoruz. Muhasebe toplantısına gitmeden 5 saniyede bu çıktıyı almak, inanın, çok rahatlatıcı.
Aylık Fatura Trendleri
Departman özeti yetmez, ay ay trend görmek de lazım. Özellikle bütçe toplantılarında “bu ay geçen aya göre nasıl?” sorusu mutlaka gelir.
awk -F',' 'NR>1 {
split($2, tarih, "-")
ay = tarih[1] "-" tarih[2]
aylik[ay] += $5
if ($8 == "Beklemede") bekleyen[ay] += $5
if ($8 == "Iptal") iptal[ay] += $5
}
END {
for (a in aylik) {
printf "Ay: %s | Toplam: %.2f TL | Bekleyen: %.2f TL | Iptal: %.2f TLn",
a, aylik[a], bekleyen[a]+0, iptal[a]+0
}
}' faturalar.csv | sort
split() fonksiyonu burada kritik. Tarih alanını “-” üzerinden parçalara ayırıp sadece yıl-ay bilgisini alıyoruz. bekleyen[a]+0 ifadesi ise o ay için bekleyen fatura yoksa sıfır göstermesini sağlar, aksi halde boş çıkar.
Zaman Çizelgesinden Maliyet Raporu
İnsan kaynakları ve proje yöneticilerinin en sevdiği konu: kim kaç saat çalıştı, ne kadar maliyet oluştu? Bu soruyu awk ile yanıtlamak son derece kolay.
awk -F',' 'NR>1 {
calisan[$2] += $7
ucret[$2] += $7 * $8
dept_saat[$3] += $7
dept_maliyet[$3] += $7 * $8
}
END {
print "n=== CALISAN BAZLI OZET ==="
for (c in calisan) {
printf "%-20s | Toplam Saat: %5.1f | Maliyet: %8.2f TLn",
c, calisan[c], ucret[c]
}
print "n=== DEPARTMAN BAZLI OZET ==="
for (d in dept_saat) {
printf "%-15s | Toplam Saat: %5.1f | Toplam Maliyet: %8.2f TLn",
d, dept_saat[d], dept_maliyet[d]
}
}' zamancizelgesi.csv
Dikkat ederseniz iki farklı özeti tek awk çalıştırmasında üretiyoruz. Önce çalışan bazlı, sonra departman bazlı. Veriler bir kez okunuyor, iki tablo üretiliyor. Performans açısından büyük dosyalarda bu yaklaşım çok önemli.
Günlük Ortalama ve Fazla Mesai Hesabı
Standart 8 saatin üzerindeki çalışmayı fazla mesai olarak işaretlemek ve raporlamak da sıkça yapılan bir iş.
awk -F',' 'NR>1 {
normal = ($7 > 8) ? 8 : $7
fazla = ($7 > 8) ? ($7 - 8) : 0
normal_ucret[$2] += normal * $8
fazla_ucret[$2] += fazla * $8 * 1.5
toplam_fazla[$2] += fazla
}
END {
print "Calisan | Normal Ucret | Fazla Mesai Ucreti | Fazla Mesai Saati"
print "--------|--------------|--------------------|-----------------"
for (c in normal_ucret) {
printf "%-20s | %10.2f | %18.2f | %5.1f saatn",
c, normal_ucret[c], fazla_ucret[c]+0, toplam_fazla[c]+0
}
}' zamancizelgesi.csv
Türkiye’deki iş kanununa göre fazla mesai ücreti en az 1.5 kat olmalı, bunu da hesaba kattım. Gerçek hayatta bu katsayıyı bir değişkene alıp dışarıdan parametre olarak geçmek daha temiz olur.
Birden Fazla Dosyayı İşleme
Gerçek dünyada veriler genellikle aylık ayrı dosyalarda gelir. Ocak, Şubat, Mart… Hepsini tek seferde işlemek mümkün ve oldukça pratik.
awk -F',' '
FNR==1 { next }
{
dept[$4] += $5
if ($8 == "Odendi") odendi[$4] += $5
kaynak[FILENAME]++
}
END {
print "=== KONSOLIDE RAPOR ==="
for (f in kaynak) print "Kaynak dosya:", f, "(" kaynak[f] " kayit)"
print ""
for (d in dept) {
printf "%-15s | Toplam: %10.2f | Odenen: %10.2f | Oran: %.1f%%n",
d, dept[d], odendi[d]+0,
(dept[d] > 0 ? (odendi[d]+0)/dept[d]*100 : 0)
}
}' faturalar_ocak.csv faturalar_subat.csv faturalar_mart.csv
FNR==1 her dosyanın ilk satırını atlar (başlık satırı), FILENAME değişkeni hangi dosyanın işlendiğini gösterir. Bu şekilde üç aylık veriyi konsolide edip her departmanın tahsilat oranını da hesaplayabiliyoruz.
Koşullu Raporlama ve Uyarı Sistemi
Belirli bir tutarın üzerindeki bekleyen faturalar için uyarı üretmek istiyorsunuz diyelim. CFO her pazartesi bunları görmek istiyor.
awk -F',' -v esik=10000 'NR>1 && $8=="Beklemede" && $5+0 > esik {
printf "UYARI: %s - %s - %.2f TL - Tarih: %sn", $1, $3, $5, $2
toplam += $5
sayac++
}
END {
if (sayac > 0) {
printf "nToplam %d bekleyen yuksek tutarli faturan", sayac
printf "Toplam Bekleyen Tutar: %.2f TLn", toplam
} else {
print "Esik deger uzerinde bekleyen fatura bulunamadi."
}
}' faturalar.csv
-v esik=10000 ile eşik değerini dışarıdan parametre olarak geçiyoruz. Bu sayede aynı script’i farklı eşik değerleriyle çalıştırabilirsiniz, script’i değiştirmenize gerek yok. Cron job ile pazartesi sabahı otomatik çalıştırıp mail atmak bu yaklaşımı özellikle değerli kılıyor.
Zaman Dilimi Bazlı Verimlilik Analizi
Bu son senaryo biraz daha ileri seviye ama proje yöneticilerinin çok sevdiği bir rapor türü. Hangi saatlerde çalışma yoğunluğu var, mesai saatleri dışında giriş var mı gibi sorular.
awk -F',' 'NR>1 {
split($5, giris, ":")
saat = giris[1] + 0
if (saat < 9) erken[$2]++
else if (saat > 10) gec[$2]++
else normal[$2]++
split($6, cikis, ":")
cikis_saat = cikis[1] + 0
if (cikis_saat > 18) gec_cikis[$2]++
}
END {
print "Calisan Davranis Analizi:"
print "------------------------"
for (c in normal) {
printf "%s | Zamaninda: %d | Erken Giris: %d | Gec Giris: %d | Gec Cikis: %dn",
c, normal[c]+0, erken[c]+0, gec[c]+0, gec_cikis[c]+0
}
}' zamancizelgesi.csv
Bu tür analizleri HR departmanıyla paylaştığınızda genellikle çok ilgi görüyor. Özellikle uzaktan çalışma düzenine geçildikten sonra bu tür zaman damgası analizleri önem kazandı.
Raporları Dosyaya Yönlendirme ve Otomasyona Hazırlama
Tek seferlik çalıştırmak yetmez tabii. Bunu bir script haline getirip cron’a bağlamak gerekiyor.
#!/bin/bash
TARIH=$(date +%Y-%m-%d)
RAPOR_DIZIN="/var/reports/fatura"
mkdir -p "$RAPOR_DIZIN"
echo "Rapor tarihi: $TARIH" > "$RAPOR_DIZIN/ozet_$TARIH.txt"
echo "========================" >> "$RAPOR_DIZIN/ozet_$TARIH.txt"
awk -F',' -v tarih="$TARIH" 'NR>1 {
dept[$4] += $5
count[$4]++
if ($8 == "Beklemede") bekleyen[$4] += $5
}
END {
print "nDEPARTMAN BAZLI FATURA OZETI"
print "-----------------------------"
for (d in dept) {
printf "%-15s | Fatura: %3d | Toplam: %10.2f | Bekleyen: %10.2fn",
d, count[d], dept[d], bekleyen[d]+0
}
}' /data/faturalar/*.csv >> "$RAPOR_DIZIN/ozet_$TARIH.txt"
# Raporu mail ile gonder
if command -v mail &> /dev/null; then
mail -s "Gunluk Fatura Ozet Raporu - $TARIH" [email protected] < "$RAPOR_DIZIN/ozet_$TARIH.txt"
fi
echo "Rapor olusturuldu: $RAPOR_DIZIN/ozet_$TARIH.txt"
Bunu /etc/cron.d/fatura_rapor dosyasına ekleyip her sabah 7’de çalıştırabilirsiniz:
0 7 * * 1-5 root /usr/local/bin/fatura_rapor.sh
Yaygın Hatalar ve Dikkat Edilmesi Gerekenler
Yıllar içinde karşılaştığım bazı tuzakları paylaşayım:
- Sayısal karşılaştırmada string sorunu:
$5 > 1000yerine$5+0 > 1000yazın, aksi halde string karşılaştırması yapar ve yanlış sonuç verir. - Türkçe karakter sorunları: CSV dosyası UTF-8 değilse
iconv -f ISO-8859-9 -t UTF-8ile dönüştürün,awksonrası birleştirin. - Boş alan kontrolü:
if ($5 != "") { ... }ile boş alanları filtreleyin, yoksa toplama hesapları bozulur. - Alan ayırıcısında virgül içeren veriler: Müşteri adı “ABC, Ltd” gibi tırnak içinde virgül içeriyorsa
awk‘ın basit-F','çözümü yetersiz kalır. Bu durumda öncesedile tırnak içlerini temizleyin ya da Python’ıncsvmodülüne başvurun. - Büyük dosyalarda bellek:
awktüm veriyi bellekte tutmaz ama dizi (array) kullanımı büyük veri setlerinde bellek sorununa yol açabilir. 1 milyon satır üzeri dosyalarda dikkatli olun.
Sonuç
awk ile metin tabanlı fatura ve zaman çizelgesi verilerini işlemek, doğru araçla doğru işi yapmak demek. Python veya özel raporlama araçlarına geçmeden önce terminal üzerinde bu kadar güçlü şeyler yapabildiğinizi görmek, bakış açınızı değiştirir.
Anlattığım teknikler gerçek projelerde defalarca kullandığım, üretim ortamında çalışan yaklaşımlar. Özellikle muhasebe ve HR ekipleriyle çalışan sistem yöneticileri için bu tür otomasyon scriptleri, hem onların hem de sizin hayatınızı ciddi ölçüde kolaylaştırır.
Bir adım öteye geçmek isteyenler için öneri: bu awk çıktılarını gnuplot ile görselleştirmek ya da basit HTML tablolara çevirip intranet’te yayınlamak harika bir kombinasyon oluyor. Ama o konu başka bir yazının malzemesi.
