awk ile CSV Çıktısını HTML Tabloya Dönüştürme ve Raporlama
Sistem yöneticiliğinde raporlama işleri her zaman can sıkıcı bir yer kaplar. Birisi senden “şu sunucuların disk kullanım raporu lazım, bak bir bakar mısın” der, sen de terminale oturup df -h çıktısını kopyalayıp bir yerlere yapıştırmaya çalışırsın. Ya da log dosyalarından çektiğin verileri Excel’e aktarmak için onlarca adım geçersin. İşte tam burada awk devreye giriyor. CSV çıktısını alıp doğrudan HTML tabloya dönüştürmek, hem zaman kazandırıyor hem de patrona ya da ekibe sunulabilecek bir rapor ortaya çıkıyor. Bu yazıda sıfırdan bir HTML rapor üretme pipeline’ı kuracağız.
awk’ı Neden Bu İş İçin Kullanıyoruz?
Önce şunu soralım: Python var, Perl var, hatta csvkit gibi hazır araçlar bile var. Neden awk?
Çünkü awk neredeyse her Linux sistemde yüklü geliyor. Bir production sunucusuna bağlandığında Python 3.x yoktur, pip yoktur, sanal ortam kurmak için izin yoktur. Ama awk her zaman oradadır. Ayrıca metin akışı üzerinde çalışma konusunda awk‘ın sadeliği rakipsiz. Küçük ve anlaşılır script’ler yazıp tek satırda çalıştırabiliyorsun.
Bir de şu var: awk öğrenmek zaman alıyor ama bir kez kavradıktan sonra pek çok farklı senaryoda seni kurtarıyor. CSV’den HTML’e dönüşüm ise bu aracın gerçek gücünü gösterdiği en güzel örneklerden biri.
Temel awk Yapısı ve CSV Mantığı
awk‘ta alan ayırıcısını -F parametresiyle belirtiyoruz. CSV dosyaları için bu virgül oluyor:
awk -F',' '{print $1, $2, $3}' dosya.csv
Burada $1 birinci sütun, $2 ikinci sütun anlamına geliyor. $0 ise tüm satırı temsil ediyor. NR değişkeni satır numarasını, NF ise o satırdaki alan sayısını veriyor.
awk‘ta üç temel blok var:
- BEGIN: Dosyayı okumaya başlamadan önce çalışır, HTML başlığı burada açılır
- Ana blok: Her satır için çalışır, tablo satırları burada oluşturulur
- END: Dosya bittikten sonra çalışır, HTML kapanış etiketleri burada yazılır
Bu yapıyı aklımızda tutarak ilk örneğimize geçelim.
İlk Örnek: Basit CSV’den HTML Tablosu
Elimizde şöyle bir sunucular.csv dosyası olduğunu varsayalım:
hostname,ip,os,durum
web01,192.168.1.10,Ubuntu 22.04,aktif
web02,192.168.1.11,Ubuntu 22.04,aktif
db01,192.168.1.20,CentOS 8,pasif
db02,192.168.1.21,CentOS 8,aktif
cache01,192.168.1.30,Debian 11,aktif
Bu dosyayı HTML tabloya dönüştüren en temel awk komutu:
awk -F',' '
BEGIN {
print "<html><body>"
print "<table border="1">"
}
NR==1 {
print "<tr>"
for(i=1; i<=NF; i++) print "<th>" $i "</th>"
print "</tr>"
}
NR>1 {
print "<tr>"
for(i=1; i<=NF; i++) print "<td>" $i "</td>"
print "</tr>"
}
END {
print "</table>"
print "</body></html>"
}
' sunucular.csv > rapor.html
Bu kadar. İlk satırı ( Yukarıdaki çıktı işlevsel ama çirkin. Biraz CSS ekleyelim ve raporu gerçekten sunulabilir hale getirelim: Zebra şeritleme için Peki bunu gerçek sistem verisiyle nasıl kullanırsın? Bu script’in güzel yanı şu: Disk kullanımı yüzde 75’in üzerindeyse sarı uyarı, yüzde 90’ın üzerindeyse kırmızı kritik renklendirme yapıyor. Raporu cron’a bağlayıp her sabah e-posta ile gönderebilirsin. Komutlar uzadıkça tek satırda yazmak anlamsızlaşıyor. Script’i bir dosyaya alman daha mantıklı: Bunu şöyle çalıştırıyorsun: Çoğu zaman elinizde hazır bir CSV olmaz, log dosyasından üretmeniz gerekir. Nginx access log’undan en çok istek atan IP’leri raporlayan bir örnek yapalım: Bu script’te bar chart efekti de ekledik. Her IP’nin istek sayısını, en yüksek değere göre normalize edip görsel bir çubuk olarak gösteriyoruz. Tamamen HTML/CSS, hiç JavaScript yok. Raporlarda en kullanışlı özelliklerden biri, belirli değerlerin öne çıkarılması. Mesela bir uptime raporunda yüzde 99’un altındaki değerleri kırmızı yapmak isteyebilirsin: Büyük ortamlarda tek bir CSV yetmez. Farklı kaynaklardan gelen verileri tek HTML raporunda birleştirmek isteyebilirsin: Bu script’i cron’a eklemek bir dakika: Script’lerde sık kullandığım bazı Dikkat edilmesi gereken bir nokta: Bazı sistemlerde Ayrıca CSV içindeki virgüllü değerlerde (örneğin Burada anlattıklarımı kendi ortamına uyarlarken şu yolda ilerlemeni öneririm: Önce en basit haliyle başla, düz HTML tablosu üret. Sonra CSS ekle. Sonra koşullu renklendirmeyi dene. En son cron’a bağla ve e-posta gönderimini kur. Her adımda çıktıyı tarayıcıda açıp kontrol et. Gerçek işe yararlılığı şurada: Bir kez kurduğunda haftalar boyunca dokunmadan çalışıyor. Sabah işe geldiğinde bir e-postada disk raporu, uptime raporu, güvenlik olayları raporu seni bekliyor. Bunları manuel toplamak yerine NR==1) başlık satırı olarak etiketiyle, geri kalanları ise etiketiyle yazıyoruz. Döngü kullandığımız için sütun sayısından bağımsız çalışıyor.
CSS Ekleyerek Görsel Kalite Artırmak
awk -F',' '
BEGIN {
print "<!DOCTYPE html>"
print "<html lang="tr">"
print "<head><meta charset="UTF-8">"
print "<title>Sunucu Envanter Raporu</title>"
print "<style>"
print "body { font-family: Arial, sans-serif; margin: 20px; }"
print "table { border-collapse: collapse; width: 100%; }"
print "th { background-color: #2c3e50; color: white; padding: 10px; text-align: left; }"
print "td { padding: 8px; border: 1px solid #ddd; }"
print "tr:nth-child(even) { background-color: #f2f2f2; }"
print "tr:hover { background-color: #d5e8d4; }"
print "h2 { color: #2c3e50; }"
print "</style></head><body>"
print "<h2>Sunucu Envanter Raporu</h2>"
print "<table>"
}
NR==1 {
print "<thead><tr>"
for(i=1; i<=NF; i++) print "<th>" $i "</th>"
print "</tr></thead><tbody>"
}
NR>1 {
print "<tr>"
for(i=1; i<=NF; i++) print "<td>" $i "</td>"
print "</tr>"
}
END {
print "</tbody></table>"
print "</body></html>"
}
' sunucular.csv > rapor.htmlnth-child(even), hover efekti için tr:hover ekledik. Bu haliyle tarayıcıda açıldığında gayet profesyonel duran bir tablo elde ediyorsun.Gerçek Dünya Senaryosu: Disk Kullanım Raporu
df çıktısını önce CSV formatına çevirip sonra HTML’e dönüştürelim:df -h | grep -v tmpfs | awk '
NR==1 { print "filesystem,boyut,kullanilan,bos,yuzde,mount" }
NR>1 { print $1","$2","$3","$4","$5","$6 }
' | awk -F',' '
BEGIN {
print "<!DOCTYPE html><html><head><meta charset="UTF-8">"
print "<title>Disk Kullanim Raporu</title>"
print "<style>"
print "body{font-family:monospace;margin:30px;background:#1a1a2e;color:#eee}"
print "table{border-collapse:collapse;width:100%}"
print "th{background:#16213e;color:#0f3460;color:#e94560;padding:12px}"
print "td{padding:10px;border:1px solid #333}"
print "tr:nth-child(even){background:#16213e}"
print ".uyari{color:#f39c12;font-weight:bold}"
print ".kritik{color:#e74c3c;font-weight:bold}"
print "</style></head><body>"
print "<h2>Disk Kullanim Raporu - " strftime("%d.%m.%Y %H:%M") "</h2>"
print "<table><thead><tr>"
}
NR==1 {
split($0, basliklar, ",")
for(i=1; i<=length(basliklar); i++) print "<th>" basliklar[i] "</th>"
print "</tr></thead><tbody>"
}
NR>1 {
yuzde = $5
gsub(/%/, "", yuzde)
sinif = ""
if (yuzde+0 >= 90) sinif = "kritik"
else if (yuzde+0 >= 75) sinif = "uyari"
print "<tr>"
for(i=1; i<=NF; i++) {
if (i==5 && sinif != "") print "<td class="" sinif "">" $i "</td>"
else print "<td>" $i "</td>"
}
print "</tr>"
}
END {
print "</tbody></table></body></html>"
}
' > disk_raporu_$(date +%Y%m%d).htmlawk Script Dosyası Kullanımı
# rapor.awk dosyasi
BEGIN {
FS = ","
print "<!DOCTYPE html>"
print "<html><head><meta charset="UTF-8">"
printf "<title>%s</title>n", baslik
print "<style>body{font-family:sans-serif}table{width:100%;border-collapse:collapse}"
print "th{background:#34495e;color:white;padding:10px}td{padding:8px;border:1px solid #ccc}"
print "tr:nth-child(even){background:#ecf0f1}</style></head><body>"
printf "<h1>%s</h1>n", baslik
print "<table>"
satir_sayisi = 0
}
NR==1 {
print "<thead><tr>"
for(i=1; i<=NF; i++) printf "<th>%s</th>", $i
print "</tr></thead><tbody>"
}
NR>1 {
satir_sayisi++
print "<tr>"
for(i=1; i<=NF; i++) printf "<td>%s</td>", $i
print "</tr>"
}
END {
printf "</tbody></table><p>Toplam kayit: <strong>%d</strong></p>", satir_sayisi
printf "<p><small>Olusturulma: %s</small></p>", strftime("%d.%m.%Y %H:%M:%S")
print "</body></html>"
}awk -v baslik="Sunucu Envanteri" -f rapor.awk sunucular.csv > cikti.html-v parametresiyle dışarıdan değişken geçirebiliyorsun. Bu sayede aynı script’i farklı başlıklarla farklı CSV dosyaları için kullanabilirsin.Log Dosyasından CSV Üretip HTML’e Dönüştürmek
# Once log'dan IP frekansi CSV'si olustur
awk '{print $1}' /var/log/nginx/access.log |
sort | uniq -c | sort -rn | head -20 |
awk '{print $2","$1}' |
awk -v tarih="$(date '+%d.%m.%Y')" '
BEGIN {
FS=","
print "<!DOCTYPE html><html><head><meta charset="UTF-8">"
print "<style>"
print "body{font-family:Arial;margin:20px;background:#f5f5f5}"
print ".kutu{background:white;padding:20px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}"
print "table{width:100%;border-collapse:collapse;margin-top:15px}"
print "th{background:#2980b9;color:white;padding:12px;text-align:left}"
print "td{padding:10px;border-bottom:1px solid #eee}"
print "tr:first-child th{border-radius:4px 4px 0 0}"
print ".bar{background:#3498db;height:18px;border-radius:3px}"
print "</style></head><body><div class="kutu">"
print "<h2>Nginx - En Cok Istek Atan IP Adresleri</h2>"
printf "<p>Rapor tarihi: %s</p>n", tarih
print "<table><thead><tr><th>IP Adresi</th><th>Istek Sayisi</th><th>Gorsel</th></tr></thead><tbody>"
max_istek = 0
}
NR==1 { max_istek = $2 }
{
if (max_istek > 0) yuzde = int(($2 / max_istek) * 200)
else yuzde = 0
printf "<tr><td>%s</td><td>%s</td>", $1, $2
printf "<td><div class="bar" style="width:%dpx"></div></td></tr>n", yuzde
}
END {
print "</tbody></table></div></body></html>"
}
' > nginx_ip_raporu.htmlKoşullu Renklendirme ve Veri Doğrulama
# uptime.csv ornegi:
# servis,uptime_yuzde,son_kesinti,sorumlu
# web-api,99.95,2024-01-05,[email protected]
# payment-svc,98.20,2024-01-12,[email protected]
# auth-svc,100,hiç,[email protected]
awk -F',' '
BEGIN {
print "<!DOCTYPE html><html><head><meta charset="UTF-8">"
print "<style>"
print "body{font-family:Arial;margin:25px}"
print "table{border-collapse:collapse;width:100%}"
print "th{background:#2c3e50;color:white;padding:12px;text-align:center}"
print "td{padding:10px;border:1px solid #ddd;text-align:center}"
print ".iyi{background:#d5f5e3;color:#1e8449;font-weight:bold}"
print ".orta{background:#fef9e7;color:#d68910;font-weight:bold}"
print ".kotu{background:#fdedec;color:#c0392b;font-weight:bold}"
print ".mukemmel{background:#eaf2ff;color:#1a5276;font-weight:bold}"
print "</style></head><body>"
print "<h2>Servis Uptime Raporu</h2><table><thead><tr>"
}
NR==1 {
for(i=1; i<=NF; i++) print "<th>" $i "</th>"
print "<th>Durum</th></tr></thead><tbody>"
}
NR>1 {
uptime = $2 + 0
if (uptime == 100) { sinif = "mukemmel"; etiket = "Mukemmel" }
else if (uptime >= 99.9) { sinif = "iyi"; etiket = "Iyi" }
else if (uptime >= 99) { sinif = "orta"; etiket = "Dikkat" }
else { sinif = "kotu"; etiket = "Kritik!" }
print "<tr>"
for(i=1; i<=NF; i++) {
if (i==2) printf "<td class="%s">%%%s</td>", sinif, $i
else printf "<td>%s</td>", $i
}
printf "<td class="%s">%s</td></tr>n", sinif, etiket
}
END {
print "</tbody></table></body></html>"
}
' uptime.csv > uptime_raporu.htmlBirden Fazla CSV’yi Tek Raporda Birleştirmek
#!/bin/bash
# coklu_rapor.sh
TARIH=$(date '+%d.%m.%Y %H:%M')
CIKTI="ozet_rapor_$(date +%Y%m%d).html"
# HTML basligi
cat > $CIKTI << 'EOF'
<!DOCTYPE html>
<html><head><meta charset="UTF-8">
<title>Sistem Ozet Raporu</title>
<style>
body{font-family:Arial;margin:20px;background:#ecf0f1}
.bolum{background:white;margin:20px 0;padding:20px;border-radius:8px;box-shadow:0 2px 6px rgba(0,0,0,0.1)}
h2{color:#2c3e50;border-bottom:2px solid #3498db;padding-bottom:8px}
table{width:100%;border-collapse:collapse}
th{background:#34495e;color:white;padding:10px}
td{padding:8px;border:1px solid #ddd}
tr:nth-child(even){background:#f8f9fa}
</style></head><body>
EOF
echo "<h1>Sistem Ozet Raporu - $TARIH</h1>" >> $CIKTI
# Disk bolumu
echo '<div class="bolum"><h2>Disk Kullanimi</h2>' >> $CIKTI
df -h | grep -v tmpfs | tail -n +2 |
awk 'BEGIN{print "<table><tr><th>Dosya Sistemi</th><th>Boyut</th><th>Kullanilan</th><th>Bos</th><th>%</th><th>Mount</th></tr>"}
{print "<tr><td>"$1"</td><td>"$2"</td><td>"$3"</td><td>"$4"</td><td>"$5"</td><td>"$6"</td></tr>"}
END{print "</table>"}' >> $CIKTI
echo '</div>' >> $CIKTI
# Bellek bolumu
echo '<div class="bolum"><h2>Bellek Kullanimi</h2>' >> $CIKTI
free -h | awk 'BEGIN{print "<table><tr><th>Tur</th><th>Toplam</th><th>Kullanilan</th><th>Bos</th></tr>"}
NR>1{print "<tr><td>"$1"</td><td>"$2"</td><td>"$3"</td><td>"$4"</td></tr>"}
END{print "</table>"}' >> $CIKTI
echo '</div>' >> $CIKTI
# Kapanisi
echo '</body></html>' >> $CIKTI
echo "Rapor olusturuldu: $CIKTI"# Her gun saat 07:00'de rapor olustur ve mail gonder
0 7 * * * /opt/scripts/coklu_rapor.sh &&
mail -s "Gunluk Sistem Raporu" -a "Content-Type: text/html"
[email protected] < /opt/raporlar/ozet_rapor_$(date +%Y%m%d).htmlÖnemli awk Parametreleri ve Notlar
awk özelliklerini not düşeyim:BEGIN içinde FS="," şeklinde de ayarlanabilirgawk‘ta çalışır, standart awk‘ta olmayabilirstrftime için gawk gerekiyor. Ubuntu ve modern dağıtımlarda awk zaten gawk‘a symlink edilmiş oluyor. Eğer değilse gawk paketini kur."New York, USA" gibi tırnak içi virgüller) basit awk çözümü sorun çıkarabilir. Bu durumda ya değerleri önceden temizlemen ya da FPAT kullanman gerekiyor:# Tirnak icindeki virgulleri dogru parse etmek icin
gawk 'BEGIN { FPAT = "([^,]+)|("[^"]+")" } { print $1, $2 }' dosya.csvSonuç
awk ile CSV’den HTML rapor üretmek, sistem yöneticisinin araç kutusundaki en değerli becerilerden biri. Hiçbir ek paket kurmadan, sadece birkaç satır script ile yöneticiye, müşteriye ya da ekibe sunulabilecek kalitede raporlar üretebiliyorsun.awk senin için yapıyor. Zamanın daha değerli işlere kalıyor.
