Hvordan (og hvorfor) å gjøre matte med awk

Awk er et ærverdig skriptspråk, skrevet for å automatisere tekstbehandling på 70-tallet, da grafiske grensesnitt for desktop og regneark, eller databaser utenfor mainframes, nesten var ukjente: er det fornuftig å bruke det til å behandle tall i disse dager?

Etter min mening gjør det det - i hvert fall for Gnu / Linux-servere og stasjonære maskiner der mange av numrene du kanskje vil behandle allerede er lagret i ren tekstfiler uansett, eller er veldig enkle å få tak i i det formatet.

Å jobbe på denne måten frigjør deg også fra behovet for å installere en database og lære hvordan du bruker den. Når alt du ønsker er noen få tall for å tegne en graf eller starte et annet skript, kan et tekstbehandlingsskript gjøre jobben raskt nok til at du ikke vil merke noen forskjell i ytelsen, og vil være mye raskere å sette opp.

I slike scenarier er awk et godt valg fordi det er:

  • Bærbar . awk kreves av Linux Standard Base-spesifikasjonen og siterer Wikipedia-siden sin, "foruten Bourne Shell, det eneste andre skriptspråket som er tilgjengelig i et standard Unix-miljø."
  • Lett . awk er lettere på systemressursene enn Perl, i det minste med små skript som er kalt mange ganger for å utføre enkle rutiner
  • Automatisert . awk-kommandoer er enkle å generere automatisk fra andre skript
  • Gnuplot-kompatibel . Måten awk fungerer på, gjør det enkelt å ringe det fra Gnuplot, for å lage grafer.
  • Fullt utstyrt . awk har nok mattefunksjoner til å gjøre de fleste brukere glade

Nå som jeg har oppsummert grunnene til å behandle tall med awk, er her et praktisk eksempel på hvordan du gjør det. Av grunner som ikke er relevante her, forsto jeg nylig at jeg trengte å vite både det rullende gjennomsnittet, beregnet over 7 dager, av unike besøk på tre websider jeg har, og hvilken prosentandel av de besøkende som går til hver av disse sidene. Jeg har et cron-skript som kjøres en gang per dag, for å lagre besøkene på hver side i en fil med fire mellomromskilte kolonner. Den første kolonnen er datoen, og de andre er antall besøk på hver side:

 20110827 89 225 331 
 20110828 124 418 635 
 20110829 176 595 827 
 20110830 174 488 730 
 20110831 153 681 967 
 ... 

Jeg behandler disse tallene for å få informasjonen jeg vil ha med et enkelt awk-skript, opprinnelig avledet av dette bølgende gjennomsnittlige trikset. Her er min utvidede versjon:

 1 #! / Usr / bin / awk -f 
 2 BEGIN {størrelse = 7} { 
 3 mod = NR% størrelse 
 4 dagers total = $ 2 + $ 3 + $ 4 
 5 perc_2 = 100 * ($ 2 / dagtotal) 
 6 perc_3 = 100 * ($ 3 / dagtotal) 
 7 perc_4 = 100 * ($ 4 / dagtotal) 
 8 hvis (maks 
 9 hvis (NR <= størrelse) {count ++} 
 10 andre {sum- = matrise mod} 
 11 sum + = dagtotal 
 12 array mod = dagtotal 
 13 printf "% 8.8s% 5.5s% 5.5s% 5.5s% 5.2f% 5.2f% 5.2f% 5.5s% 5.0f \ n", $ 1, $ 2, $ 3, $ 4, perc_2, perc_3, perc_4, daytotal, summen / telling} 
 14 SLUTT {skriv ut '# topptrafikk på', maksdag, ': ", maks, " besøk "} 

Linje 2 og 14 er, eller bør være, selvforklarende. Som standard fungerer awk på en tekststrøm, en linje om gangen: alle kommandoene i et awk-skript brukes som de er på hver linje. Imidlertid, hvis du vil gjøre noe før eller etter å ha behandlet alle disse linjene, kan du gjøre det. Sett i seler rett etter BEGIN-nøkkelordet hva som må skje før start, og merk med END hva som må gjøres når det ikke er flere innspill. I skriptet mitt initialiserer jeg størrelsen på det rullende gjennomsnittsvinduet til 7, og ber skriptet om å skrive ut noen sammendragsdata rett før jeg avslutter.

Den sentrale delen av skriptet viser at du kan fortelle awk å utføre beregninger på en relativt intuitiv måte, når du først vet noen få grunnleggende nøkkelord. I awk har den spesielle NR-variabelen antall poster som allerede er behandlet (som standard er hver linje i tekstinnmatingsstrømmen én post). Variablene som heter $ N ($ 1, $ 2 og så videre) inneholder alltid verdien av felt N for den nåværende posten. Derfor er linje 4 til 7 alt jeg trenger for å beregne det totale antallet besøk hver dag, og hvor mye hver side bidrar til den trafikken. Jeg ber også awk om å lagre det høyeste antallet besøk og dagen da de skjedde i maks- og maxdag-variablene (linje 8), slik at det kan skrives ut senere (linje 14).

Som det skjer på andre språk, er '%' moduloperatøren. Den brukes i linje 3 for å lage en indeks, mod, som kontinuerlig går mellom verdiene 0 og "størrelse - 1", det vil si 6.

For å beregne et rullende gjennomsnitt over en uke, må vi per definisjon summere alle besøkene mottatt på en gitt dag og de 6 foregående, og deretter dele dette tallet med 7. Skriptet oppnår dette med tre variabler: telling er delingsfaktoren, som er lik maksimum mellom størrelse og NR. summen er, som navnet sier, summen av alle besøkene den siste uken. array, i stedet, er en matrise laget av 7 elementer, som hver inneholder totalt besøk for en av de siste 7 dagene.

Hver gang awk laster en linje fra inndatafilen, trekker den fra summen av besøkene som skjedde en uke før (linje 10), og legger deretter til den for dagens dato (linje 11). Den neste linjen erstatter i matrisen besøkene som ble mottatt syv dager tidligere med det gjeldende dagsnotatet. Til slutt skriver linje 13 ut alt i bestilte kolonner, klare til å bli plottet eller behandlet på andre måter, takket være awk printf-kommandoen:

 20110915 345 949 1412 12, 75 35, 07 52, 18 2706 1982 
 20110916 627 1330 2502 14.06 29.83 56.11 4459 2392 
 20110917 841 1162 3265 15, 96 22.06 61, 98 5268 2918 
 20110919 600 1361 2446 13.61 30.88 55.50 4407 3367 
 20110920 118 221 380 16.41 30, 74 52, 85 719 3111 
 # topptrafikk 20110917: 5268 besøk 
Hvis du er nysgjerrig, viser figur A disse tidsbaserte dataene plottet med Gnuplot-teknikkene jeg forklarte tidligere.

© Copyright 2020 | mobilegn.com