Ders 17 / 24
Alan Tabanlı İşleme
Kayıt ve alan modeli, kalıp–eylem yapısı, yerleşik değişkenler, ilişkisel dizilerle birikim ve tek geçişte rapor üretimi.
İçindekiler
Akış editörü satırı bir metin olarak görür; alanları ancak kalıpla taklit edebilir. Kütükteki dokuzuncu alanı almak için satırın tamamını betimleyen bir kalıp yazmak gerekmişti ve o kalıp, biçim küçük bir değişikliğe uğradığında bozulur.
Sütunlu veri için ayrı bir araç sınıfı vardır. Alan tabanlı işleme aracı, girdiyi kayıtlara, kayıtları alanlara böler ve kalıp–eylem çiftlerinden oluşan bir program yürütür. Bu ders o modeli kurar ve önceki konuda ilişkisel dizilerle yazılan sayımları tek satıra indirir.
Kayıt ve Alan Modeli
Girdi öntanımlı olarak satırlara — kayıtlara — bölünür. Her kayıt, boşluk kümelerine
göre alanlara ayrılır. $1 birinci alanı, $0 kaydın tamamını, $NF son alanı
verir.
head -2 erisim.log | awk '{ print NR, NF, $1, $9, $NF }'
1 10 10.0.0.12 200 5120 2 10 10.0.0.31 200 2048
Yerleşik değişkenler modelin çevresini tamamlar:
| Değişken | İçerik |
|---|---|
NR |
okunan kayıt sayısı (dosyalar boyunca birikir) |
FNR |
o dosyadaki kayıt sırası |
NF |
o kayıttaki alan sayısı |
FS |
alan ayırıcısı (öntanımlı: boşluk kümeleri) |
OFS |
çıktı alan ayırıcısı (öntanımlı: tek boşluk) |
FILENAME |
okunmakta olan dosyanın adı |
Öntanımlı ayırıcının “boşluk kümeleri” olması önemlidir: art arda gelen boşluklar tek
ayırıcı sayılır ve satır başındaki boşluklar yok sayılır. Bu, cut komutundan ayrıldığı
noktadır — cut her ayırıcıyı ayrı sayar ve hizalanmış metinlerde boş alanlar üretir.
Kalıp ve Eylem
Program, kalıp { eylem } çiftlerinden oluşur. Kayıt kalıba uyuyorsa eylem çalışır.
awk '$9 >= 500 { print $1, $7, $9 }' erisim.log
192.168.1.5 /api/veri 500 192.168.1.5 /api/veri 500 10.0.2.7 /api/veri 500
İki bölüm de isteğe bağlıdır ve eksik olan yerine varsayılan konur:
- Kalıp yazılmazsa eylem her kayda uygulanır.
- Eylem yazılmazsa varsayılan eylem
{ print }olur.
awk '$9 == 404' erisim.log | grep -c ''
4
Kalıp bir düzenli ifade de olabilir. /kalıp/ tüm kaydı, $9 ~ /kalıp/ belirli bir alanı
sınar:
awk '$9 ~ /^[45]/ { n++ } END { print n }' erisim.log
Programın tamamı tek tırnak içinde yazılır. Programda $ işareti alan başvurusudur;
çift tırnak kullanılırsa kabuk onu değişken genişletmesi sanar ve program bozulur. Bu,
Değişkenler ve Tırnak Kuralları dersindeki kuralın en sık gerekli olduğu yerdir.
BEGIN ve END
BEGIN bloğu ilk kayıt okunmadan, END bloğu son kayıttan sonra çalışır. Başlık yazmak,
ayar yapmak ve birikimleri raporlamak için kullanılır.
awk '
BEGIN { print "adres bayt" }
{ t += $10 }
END { printf "toplam: %d bayt, %d istek, ortalama %.1f\n", t, NR, t / NR }
' erisim.log
adres bayt toplam: 117780 bayt, 30 istek, ortalama 3926.0
Değişkenler bildirilmeden kullanılır; ilk kullanımda sayısal bağlamda sıfır, dizgi
bağlamında boş dizi değerindedirler. t += $10 satırı bu yüzden ayrı bir ilklendirme
gerektirmedi.
printf biçimlendirmesi, kabuğun printf komutuyla aynı belirteçleri kullanır ve
ondalıklı sayı basabilir — kabuk aritmetiğinin tam sayı kısıtı burada yoktur.
İlişkisel Diziler
Diziler yalnızca ilişkiseldir ve bildirim gerektirmez. Anahtar başına sayım, önceki konudaki kabuk döngüsünün tek satırlık karşılığıdır:
awk '{ sayim[$7]++ } END { for (y in sayim) printf "%3d %s\n", sayim[y], y }' erisim.log \ | sort -rn | head -5
6 /api/veri 4 /yok.html 4 /index.html 3 /urun/45 3 /urun/12
Anahtar başına toplam da aynı desendir:
awk '{ bayt[$7] += $10 } END { for (y in bayt) printf "%8d %s\n", bayt[y], y }' erisim.log \ | sort -rn | head -5
36120 /panel
25230 /urun/12
21990 /urun/45
20480 /index.html
7236 /api/veri
for (anahtar in dizi) döngüsünün ürettiği sıra tanımsızdır; sıralı çıktı için dışarıdan
sort gerekir. Bu, ilişkisel dizilerin karma tablosuyla gerçekleştirilmesinin doğrudan
sonucudur ve Veri Yapıları kursunda tanımlanmıştı.
Alan Ayırıcısını Değiştirmek
-F seçeneği alan ayırıcısını belirler. Değer tek karakter ya da düzenli ifade olabilir.
printf 'a:b:c\nd:e:f\n' | awk -F: '{ print $2 }'
b e
Çıktı ayırıcısı ayrı bir değişkendir:
head -2 erisim.log | awk 'BEGIN { OFS="|" } { print $1, $7, $9 }'
10.0.0.12|/index.html|200 10.0.0.31|/statik/stil.css|200
print komutunda alanlar virgülle ayrılır; virgül OFS ile yer değiştirir. Virgül
yerine boşluk yazılırsa alanlar ayırıcısız bitiştirilir — bu, dizgi birleştirmenin
yazımıdır ve sessiz bir hata kaynağıdır.
Bir alana atama yapmak kaydı yeniden kurar:
head -1 erisim.log | awk '{ $1="GIZLI"; print }' | cut -c1-45
GIZLI - - [07/Feb/2024:09:12:44 +0000] "GET /
Kayıt yeniden kurulurken alanlar OFS ile birleştirilir; özgün satırdaki çoklu boşluklar
korunmaz. Alan gizleme ve maskeleme işlemlerinde beklenen davranış budur.
Sayı ve Dizgi Bağlamı
Alanlar hem sayı hem dizgi olarak yorumlanabilir; hangi yorumun uygulanacağı işlecin türüne ve işlenenlerin kaynağına bağlıdır. Girdiden gelen bir alan sayı gibi görünüyorsa sayısal karşılaştırılır; ancak dizgi sabitleriyle karşılaştırıldığında dizgi bağlamı kazanabilir.
awk 'BEGIN { x="10"; y="9"; print (x > y ) ? "dizgi: 10>9" : "dizgi: 10<9" }' awk 'BEGIN { x="10"; y="9"; print (x+0 > y+0) ? "sayi: 10>9" : "sayi: 10<9" }'
dizgi: 10<9 sayi: 10>9
Belirsizliği ortadan kaldırmanın yolu bağlamı açıkça zorlamaktır: sayısal karşılaştırma
için +0, dizgi karşılaştırması için "" ile birleştirme. Dış kaynaklı veriyle çalışan
programlarda bu alışkanlık, açıklaması güç sonuçları önler.
Kabuk Değişkeni Aktarmak
Kabuk değişkenleri program metnine gömülmez; -v seçeneğiyle aktarılır.
esik=400 awk -v esik="$esik" '$9 >= esik { n++ } END { print n " istek " esik " ve uzeri" }' erisim.log
9 istek 400 ve uzeri
Değeri program metnine gömmek — tırnakları kapatıp açarak — iki nedenle yanlıştır:
değerdeki tırnak ve ters bölü karakterleri programı bozar, ve dışarıdan gelen bir değer
program kodu hâline gelerek istenmeyen komutlar çalıştırabilir. -v bu sınırı korur.
Bozuk Kayıtları Yakalamak
Alan sayısı, biçim doğrulamasının en ucuz ölçütüdür:
awk 'NF != 10 { print FILENAME ":" FNR ": alan sayisi " NF }' tumu.log
tumu.log:31: alan sayisi 2 tumu.log:32: alan sayisi 9
Düzenli İfadeler dersinde aynı iş satırın tamamını betimleyen bir kalıpla yapılmıştı. Alan sayısı sınaması daha dar bir doğrulama yapar ama çok daha kısa yazılır ve biçim değişikliklerine dayanıklıdır. İkisi birlikte kullanılabilir: alan sayısı hızlı eleme, kalıp ayrıntılı doğrulama içindir.
Çok Kalıplı Program
Programda birden çok kalıp–eylem çifti bulunabilir; her kayıt tüm çiftlere karşı sırayla sınanır.
awk ' $9 ~ /^2/ { basarili++ } $9 ~ /^[45]/ { hata++; hatali_yol[$7]++ } END { printf "basarili=%d hata=%d\n", basarili, hata for (y in hatali_yol) printf " %-14s %d\n", y, hatali_yol[y] } ' erisim.log | sort
/api/veri 3 /gizli 2 /yok.html 4 basarili=18 hata=9
Bir kayıt birden çok kalıba uyuyorsa ilgili tüm eylemler çalışır; case yapısındaki “ilk
eşleşen dal” kuralı burada geçerli değildir.
Betiğe Uygulama
rapor.sh şu ana dek her sayım için kütüğü baştan okuyordu: satır sayımı, bayt toplamı ve
dört durum sınıfı için altı ayrı geçiş. Hepsi tek geçişe iner:
kutuk=erisim.log awk -v adet="$adet" ' { istek++; bayt += $10; yol[$7]++; sinif[substr($9, 1, 1)]++ } END { printf "istek : %d\n", istek printf "bayt : %d\n", bayt printf "ortalama: %.1f bayt\n", (istek ? bayt / istek : 0) print "" print "durum kodu siniflari:" for (s = 2; s <= 5; s++) printf " %sxx %4d %%%.1f\n", s, sinif[s], (istek ? sinif[s] * 100 / istek : 0) } ' "$kutuk"
istek : 30 bayt : 117780 ortalama: 3926.0 bayt durum kodu siniflari: 2xx 18 %60.0 3xx 3 %10.0 4xx 6 %20.0 5xx 3 %10.0
Üç kazanç var. Kütük bir kez okunuyor. Yüzdeler ondalıklı ve ölçeklendirme hilesi gerekmiyor. Sıfıra bölme koruması, kabuktaki üçlü işleçle aynı biçimde yazılıyor.
Kayıp da var: rapor mantığının bir bölümü artık kabukta değil, gömülü bir programda. Betiğin okunurluğu, bu programın kısa ve tek amaçlı kalmasına bağlıdır. İki yüz satırlık gömülü programlar, kabuk betiğinin sınırının aşıldığının işaretidir.
Özet
- Girdi kayıtlara, kayıtlar alanlara bölünür;
$0kaydın tamamı,NFalan sayısı,NRkayıt sırasıdır. Öntanımlı ayırıcı boşluk kümeleridir. - Program
kalıp { eylem }çiftlerinden oluşur; kalıp yoksa her kayda, eylem yoksaprintuygulanır ve kayıt tüm çiftlere karşı sınanır. BEGINveENDblokları kayıt akışının dışında çalışır; değişkenler bildirimsizdir ve sıfırdan başlar.- İlişkisel dizilerle anahtar başına sayım ve toplam tek satırda yazılır; gezinme sırası tanımsızdır.
- Kabuk değerleri program metnine gömülmez,
-vile aktarılır. - Sayı ve dizgi bağlamı işlenenlere bağlıdır;
+0ve""ile açıkça zorlanır.
Sonraki Adım
Sayımlar üretildi ama sıralanmaları hep dış bir komuta bırakıldı. Sonraki ders o komutu ve yanındaki iki aracı ele alır: anahtara göre sıralama, komşu yinelemeleri tekilleştirme ve iki sıralı akışı küme işlemleriyle karşılaştırma — ayrıca sıralamanın yerel ayara bağlı olmasının betiklerde neden bir hata kaynağı olduğunu.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.