AWK

pattern scanning and text processing language

Introductie

awk is een zogenaamde geïnterpreteerde programmeertaal, het is enorm krachtig en ontwikkeld voor het verwerken van tekst. De naam is afgeleid van de familienaam van de ontwikkelaars: Alfred Aho, Peter Weinberger en Brian Kernighan.

De versie van awk die bij de Linux distributies geleverd wordt is de versie van de Free Software Foundation, beter bekend als GNU AWK.

Er bestaan dus verschillende versies van awk:
  • AWK De orginele AWK van Bell Labs van AT&T
  • NAWK Nieuwe en verbeterde versie van AWK, ook van Bell Labs van AT&T
  • GAWK GNU Awk. Alle GNU/Linux distributies komen met de versie van AWK, GAWK is volledig compatibel met AWK en NAWK.
Waarvoor gebruiken we AWK:
  • Tekst verwerking
  • Het maken van rapporten die aan een bepaalde indeling moeten voldoen
  • Wiskundige berekeningen uitvoeren
  • Bewerkingen op tekenreeksen uitvoeren
  • ...

Workflow

AWK werkt als volgt

Figuur 1. AWK Workflow
AWK Workflow
  • Voer uit: Alle awk commando's worden in volgorde toegepast op de input (record en field). Standaard voert awk de commando's uit op alle records/regels, maar dit kan door het gebruik van patronen aangepast worden.
  • Herhaal: Het lees en voer uit proces wordt herhaaldelijk uitgevoerd tot het einde van het bestand bereikt is.

AWK leest een lijn uit de input stream (bestand, standard input (stdin) of pipe) en bewaart deze in het geheugen.

De invoer wordt opgedeeld in records en fields.

Een record is een stroom aan invoer waarop awk werkt, een record wordt beëindigd door een zogenaamde record separator welke wordt opgeslagen in de RS variabele. Standaard is dit ingesteld op een nieuwe regel. Dus een volledig regel wordt gezien als 1 record. De invoer wordt als volgt opgedeeld

Figuur 1. Input data wordt verdeeld in Records
Input data wordt verdeeld in Records
De records worden verder onderverdeeld in fields, net zoals records worden fields gelimiteerd door een einde-teken, bij een field is dat standaard ieder vorm van "whitespace", (1 of meer spaties, een TAB, ...) dus standaard wordt iedere regel tekst opgedeeld per woord. We kunnen dit als volgt zien
Figuur 3. Records worden opgedeelt in fields
Records worden opgedeelt in fields

Het laatste field is speciaal, dit bevat het aantal velden in het record in de variabele NF. Dit veld kunnen we benaderen met zijn nummer en met de speciale variabele NF.

Een volledige awk workflow kunnen we als volgt voorstellen
Figuur 4. Volledige AWK workflow
Volledige AWK workflow

Gebruik

Patroon structuur

Een AWK programma bestaat uit een of meerdere patronen gevolgd door een uit te voeren actie. Deze action-pattern statements worden gescheiden door een newline teken. Zowel het awk commando als het zoek patroon zijn optioneel en staan tussen accolades ({):

/ zoek patroon : {actie / awk-commando} /zoek patroon / {actie awk-commando}.

awk leest iedere regel en als het een overeenkomst vindt met een zoek patroon dan wordt de daarbij horende actie uitgevoerd. Daarna wordt de volgende regel ingelezen en gaat awk door tot het einde van het bestand.

In de awk syntaxis mogen we voor een pattern-action statement het patroon of de actie weglaten, maar niet beide. Als het zoek patroon geen bijhorende actie heeft (een awk commando) dan wordt iedere regel die voldoet aan het zoekpatroon naar de output geschreven (bijv. de monitor)

Omdat AWK is programmeertaal is gaat het onmogelijk zijn om alle mogelijkheden te bespreken, zelfs al is het maar kort aanhalen wat je allemaal kunt doen.

Voorbeeld bestand

Om enkele voorbeelden te kunnen geven gaan we gebruik maken van een voorbeeld tekst bestand waarop we awk kunnen loslaten. Dit bestand bevat de volgende (fictieve) gegevens:

naam, Telefoonnummer, e-mailadres, functie en FTP toegang (Y of N)
Patrick +3247999999 patk@commandoregel.be cm y
Bernard +3169999998 bernf@commandoregel.be fb n
Corne +32478999999 corns@commandoregel.be fb n
Richard +316987987 ricvns@gmail.com fb n
Johan +3247987654 johja@commandoregel.be wm y

Enkel een zoekpatroon

Een awk-commando met enkel een zoekpatroon ziet er als volgt uit: awk '/ patroon /' bestandsnaam

Als we dit toepassen op ons databestand, kunnen we bijvoorbeeld zoeken naar het teamlidRichard:

awk '/Richard/' team.txt
Figuur 5. awk '/Richard/' team.txt
awk '/Richard/' team.txt

Enkel en commando

Willen we enkel een commando geven, zonder zoekpatroon (zodat dit commando op iedere regel wordt toegepast) dan is het commando daarvoor: awk '{ actie / awk-commando }' bestandsnaam.

Hiermee kunnen we bijvoorbeeld alle namen van de teamleden weergeven:

awk '{ print $1 }' team.txt
Figuur 6. awk '{ print $1 }' team.txt
awk '{ print $1 }' team.txt
Hier geeft $1 aan dat we het eerste veld uit het record willen afdrukken op het scherm, als je hier $0 ingeeft dan zal het volledige veld worden weergegeven. Maar in dit geval kun je dan net zo goed cat gebruiken.

Behalve print $0 zijn er bij awk verschillende methoden om hetzelfde effect te hebben bijvoorbeeld:

awk '//' bestandsnaam

awk '{print}' bestandsnaam

awk '//{ print }' bestandsnaam

Het resultaat van al deze commando's is hetzelfde:

Zoekpatroon én actie

We kunnen deze 2 combineren en bijvoorbeeld zoeken naar het e-mailadres dat bij het teamlid Patrick hoort:

awk '/Patrick/{print $3}' team.txt
Figuur 7. awk '/Patrick/{print $3}' team.txt
awk '/Patrick/{print $3}' team.txt

Het BEGIN blok

Het is mogelijk om bij awk een "beginblock" in te geven, dit zal een bepaald patroon/commando 1 keer uitvoeren voor het awk-body blok begint. Hiermee kunnen we bijvoorbeeld enkele standaard awk variabelen aanpassen. Een BEGIN block wordt als volgt aan gegeven:

BEGIN { actie / awk-commandos }

Het END blok

Net zoals er een BEGIN blok is, is er ook een END block, dit zal het awk-commando 1 keer uitvoeren op het einde van de awk-workflow. Een END-Block ziet er als volgt uit:

END { actie / awk-commandos }

Het BODY blok

Tussen het BEGIN en END blok, zit natuurlijk het body-block dit bestaat uit 1 of meerdere awk patronen/commandos.

AWK-Programma

Met deze gegevens kunnen we ons eerste awk-programma gaan schrijven:
awk 'BEGIN { print "Commandoregel Team Lijst"}                 # begin blok
{ print }                                                      # body blok
END { print "--Einde van het bestand--" }' team.txt            # end block
Figuur 8. simpel awk programma
simpel awk programma

Willen we dit als awk-programma gebruiken, dan plaatsen we dit gewoon in een tekstbestand (teamlijst bijvoorbeeld) en maken het met chmod uitvoerbaar, daarna kunnen we het simpelweg opstarten met ./teamlijst:

Figuur 9. awk programma
awk programma

Soorten Patronen

Binnen patroon-actie statements bepalen de patronen wanneer een bepaalde actie moet uitgevoerd worden. We kunnen het gebruik ervan als volgt indelen:

  1. BEGIN { statement } : Een BEGIN blok dat wordt uitgevoerd voor de "body" van het awk programma
  2. END { statements } : Een END blok dat enkel wordt uitgevoerd na de "body" van het awk programma
  3. expressie { statement } : De actie wordt uitgevoerd wanneer de waarde van de expressie "waar" is (niet-nul).
  4. / regular expression / { statement } : De actie wordt uitgevoerd wanneer de waarde van de regular expression waar is. (Regular Expressions of RegEx zoals ze ook vaak genoemd worden, zijn zeer krachtige hulpmiddelen om bepaalde condities te controleren. Ze worden bij *NIX1 dan ook vaak gebruikt en dus ook bij awk).
  5. "compound patroon { statement } : Een compount patroon is samen gesteld uit 1 of meerdere logische expressies (bijvoorbeeld && [AND], || [OR], ![NOT] en haakjes ( ).
  6. patroon 1, patroon 2 { statement } : Een bereik dat overeenkomt met iedere input regel, van het begin van patroon 1 tot de volgende regel overeenkomstig patroon 2

BEGIN en END kunnen niet gecombineerd worden met andere patronen, en een "bereik-patroon (6) kan geen onderdeel vormen van een ander patroon.

BEGIN en END zijn de enige patronen waarbij een actie noodzakelijk is.

Soorten Acties

We kunnen de soorten van acties onderverdelen in de volgende groepen:
  1. Expressions: dit zijn constanten, variabelen, operatoren, functie aanroepen (bijvoorbeeld X = X + 4)
  2. Print statements: Deze bestaan uit print of printf (bijvoorbeeld print"Commandoregel.be Team Informatie".
  3. "control-flow" statements: Dit zijn "statements" die beslissingen nemen (if..else) en lussen (while, for, do) en statements om deze lussen te beheren (break, continue, next en exit).
  4. { statements }: Deze worden gebruikt om statements to groeperen in een blok.

Voorbeeld van de meester

Professor Brian w. Kernighan (de k in awk), heeft tijdens een lezing een goed voorbeeld gegeven wanneer men awk gebruikt en niet een andere programmeertaal zoals C of C++.

In zijn voorbeeld had een wetenschapper een lijst met vulkaanuitbarstingen en wilde men weten welke van deze een kracht van 6 of hoger hadden. Hieronder zie je het voorbeeld van zijn lezing (stel je nu voor dat dit een lijst is met meer dan 8.000 van deze regels.

8/27/1883    Krakatoa         8.8
5/18/1989    MountStHellen    7.6
3/13/2009    CostaRica        5.1
Een voorbeeld van een programma in C dat deze uitbarstingen filtert:
#include <stdio.h>
#include <string.h>

int main(void) {
    char line[1000], line2[1000];
    char *p;
    double mag;

    while (fgets(line, sizeof(line), stdin) != NULL {
        strcpy{ line2, line}
        p = strtok(line, "\t");
        p = strtok(NULL, "\t");
        p = strtok(NULL, "\t");
        sscan(p, "%fl", &mag);
        if (mag > 6)
            printf("%s", line2);
    }
return 0;
}

Dit programma koste hem zo'n 20 minuten om te schrijven en te debuggen, en het is niet heel robuust.

Hoe zou dit programma er uitzien indien het geschreven was in awk?

awk '$3 > 6' eruptions.txt
Figuur 10. awk '$3 > 6' eruptions.txt
awk '$3 > 6' eruptions.txt

Dit programma is niet alleen korter en duurde maar enkele seconden om te schrijven, maar is ook robuuster dan de c versie.

Conclusie: Als je een grote dataset moet beheren of bewerken dan is de kan reëel dat je met een tool als awk de beste tool in handen hebt.

Wil je meer weten over awk of wil je de programmeertaal leren neem dan zeker eens een kijkje in de manpages of de infopages. Of zoek een Website met tutorials.

Er zijn ook enkele boeken geschreven om te leren werken met awk vaak (maar niet altijd) bevatten deze boeken niet enkel informatie over awk maar ook een andere populaire tool met als naam sed.

Zie ook sed en Regular Expressions

1 Als men het heeft over UNIX®/Linux® of andere UNIX of UNIX-Achtige systemen (denk aan BSD® of macOS®) dan gebruikt men vaak *NIX om dit aan te geven).