Voorbeelden met AWK: een korte inleiding.

ArticleCategory:

UNIX Basics

AuthorImage:

[Foto van de Auteur]

AuthorName:

Javier Palacios Bermejo

AboutTheAuthor:

Onze geachte schrijver verkiest zijn publiekelijke leven met mysterie te omhullen. Vandaar dat hij anoniem blijft.

Abstract:

Dit artikel geeft inzicht in de trucs die je met AWK kan uithalen. Het is geen cursus maar levert echte, bruikbare voorbeelden.

ArticleIllustration:

[Illustratie]

ArticleBody:

Het idee voor dit artikel kwam bij me op na het lezen van een aantal artikelen in LinuxFocus, geschreven door Guido Socher. Eén daarvan, getiteld Bestanden vinden deed me realiseren dat ik niet de enige was die de commandoregel gebruikte. Maar ál te vaak laten grafische gebruikersinterfaces niet zien hoe het nu écht in zijn werk gaat (dat pad is Windows jaren geleden ingeslagen). Het andere artikel ging over reguliere expressies die je, hoewel hier slechts zijdelings behandeld, moet kennen om het meeste uit AWK en andere commando's (vooral sed en grep) te krijgen. Hamvraag hier is of het commando echt bruikbaar is. Het antwoordt is een volmondig Ja!! Het kan bruikbaar zijn voor doorsnee gebruikers voor het bewerken van tekstbestanden, het opnieuw opmaken etc... AWK is echter écht belangrijk voor de systeembeheerder. Snuffel eens wat in /var/yp/Makefile of bekijk de initialisatie scripts van een willekeurig systeem. AWK is overal.

Inleiding AWK

Mijn eerste ervaring met AWK stamt uit een ver verleden. Ik had een collega die moest werken met heel veel uitvoer van een kleine Cray. De helppagina over awk op de Cray was zeer summier, maar hij dacht dat het was wat hij hiervoor nodig had, hoewel hij nog geen flauw idee had hoe het te gebruiken.
Later in mijn leven was er een andere collega die AWK gebruikte om de eerste kolom uit een tabel te halen:
awk '{print $1}' file
Simpel hè? Deze eenvoudige taak hoeft niet, moeilijk moeilijk, in een complexe taal als C te worden geprogrammeerd, noch in enige andere gecompileerde of geïnterpreteerde taal. Eén regel awk doet het 'm.

Na de les een kolom extraheren kunnen we overgaan naar zoiets als het hernoemen van bestanden:
ls -1 pattern | awk '{print "mv "$1" "$1".new"}' | sh

...en er is meer. Het gebruik van sed of grep, in combinatie met het laatste voorbeeld, is een nog krachtiger hulpmiddel.

  1. Delen van een naam hernoemen
    ls -1 *old* | awk '{print "mv "$1" "$1}' | sed s/old/new/2 | sh
    (hoewel dit soms zal falen, zoals met het bestand file_old_and_old).

  2. Alleen bestanden en geen directories weggooien (dit kan ook door alleen rm te gebruiken, maar wat dan in het geval van een alias als rm -r)
    ls -l * | grep -v drwx | awk '{print "rm "$9}' | sh
    (ook hier kan het misgaan met rare bestandsnamen of bestandspermissies). Pas op met uitproberen in je home directory. Het haalt files weg!

  3. Alleen directories weggooien
    ls -l | grep '^d' | awk '{print "rm -r "$9}' | sh
    (Volgens mij kan dit niet fout gaan en we kunnen het nog verbeteren met:
    ls -p | grep /$ | wk '{print "rm -r "$1}')
    Pas op met uitproberen in je home directory. Het haalt files weg!

Indien we bijvoorbeeld bepaalde herhaalde berekeningen uit moeten voeren met wisselende parameters en we willen daarbij een aantal uitvoerbestanden selecteren voor verdere verwerking, dan kan dit hulpmiddel echt van dienst zijn. ...Nog afgezien van het feit dat het veel leuker is om een AWK-programma te schrijven dan het herhaaldelijk intikken van (bijna) hetzelfde commando.

Feitelijk, hoewel we het normaal gesproken zo benoemen, is awk nou niet echt wat we ons voorstellen van een commando. awk is een programmeertaal met een syntaxis die erg lijkt op C. Het is een geïnterpreteerde taal en de awk-interpretator verwerkt de instructies.

Over de syntaxis van het commando zelf:

# gawk --help
Usage: gawk [POSIX or GNU style options] -f progfile [--] file ...
        gawk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:          GNU long options:
        -f progfile             --file=progfile
        -F fs                   --field-separator=fs
        -v var=val              --assign=var=val
        -m[fr] val
        -W compat               --compat
        -W copyleft             --copyleft
        -W copyright            --copyright
        -W help                 --help
        -W lint                 --lint
        -W lint-old             --lint-old
        -W posix                --posix
        -W re-interval          --re-interval
        -W source=program-text  --source=program-text
        -W traditional          --traditional
        -W usage                --usage
        -W version              --version

Report bugs to [email protected],
with a Cc: to [email protected]
In plaats van het simpelweg aanhalen (') van het programma op de commandoregel, kunnen we dit programma ook in een bestand zetten en het aanroepen met de -f optie. Met het gebruik van variabele definities als -v var=val, kunnen we verdere flexibiliteit toevoegen aan de door ons te schrijven programma's.

AWK is min of meer een taal, toegespitst op het werken met tabellen. Dat is informatie die kan worden gegroepeerd in velden en records. Het grote voordeel hier is dat de definitie van het record (en ook van de velden) zeer flexibel kan zijn.

Maar awk is krachtig. Het is gemaakt voor het werken met records van één regel, hoewel hieraan nog wel wat valt te doen. Om een goed beeld te kunnen krijgen van dit soort aspecten, gaan we een aantal praktische voorbeelden behandelen ter illustratie.

Voor programma's als deze heb je 5 minuten nodig voor het uitdenken en nog eens 5 om het te maken (of meer dan 20 minuten zonder nadenken en veel lol met het uitproberen).

Ik heb awk voor veel doeleinden gebruikt (bijvoorbeeld voor het automatisch genereren van web pagina's met gegevens uit eenvoudige databases) en ik weet inmiddels voldoende van het programmeren in awk om te kunnen stellen dat je er heel veel taken mee kunt doen.
De enige grens is je fantasie.

Een probleem

(en een oplossing)

Een probleem is dat awk perfect tabulaire data nodig heeft, zonder 'gaten'. Met ander woorden: awk werkt niet op kolommen met een vaste breedte. Dit is geen probleem als we zelf de input voor awk genereren: neem een niet-gebruikt teken om hiermee velden te scheiden, gebruik daarna FS om het er weer uit te filteren en klaar! Maar als we de invoer al hebben kan het problemen op leveren. Met het gebruik van spaties als FS kunnen bepaalde samengestelde velden problemen geven. Bijvoorbeeld in de volgende tabel:
1234  HD 13324  22:40:54 ....
1235  HD12223   22:43:12 ....
Dit is moeilijk te behappen voor awk. Dit soort invoer kan echter voorkomen zonder dat er iets aan te doen is. Bovendien is dit normaal, de meeste invoer is niet homogeen. We kunnen het probleem met één zo'n kolom echter oplossen (als er iemand is die weet wat te doen met meerdere van dergelijke kolommen tegelijkertijd, laat het me weten!). Op een keer had ik een tabel zoals boven omschreven. De tweede kolom was een naam en kon meerder spaties hebben. Zoals dit meestal het geval is, moest het zaakje gesorteerd worden op de kolom die daarop volgde. Ik heb diverse vormen van het sort +/-n.m commando geprobeerd maar dit had hetzelfde spatie-probleem.
Opeens realiseerde ik me dat de te sorteren kolom de laatste op de regel was en awk weet hoeveel velden er op de huidige regel staan. Het was dus voldoende om het laatste veld te benaderen (dat kon $9 zijn of $11, maar altijd $NF). Aan het eind van de dag had ik het gewenste resultaat:
{
  printf $NF
  $NF = ""
  printf " "$0"\n"
}
Hiermee krijg ik uitvoer, gelijk aan de invoer, met dit verschil dat de laatste kolom nu als eerste staat. Het mag duidelijk zijn dat deze methode net zo makkelijk kan worden toegepast voor zeg, de derde kolom vanaf het einde of bij een kolom die start met een stuurteken, die altijd dezelfde waarde heeft.
Met het verplaatsen van de laatste kolom naar de eerste positie kunnen we nu sort er op los laten en eenvoudig sorteren.
Gewoon een kwestie van je creativiteit en fantasie gebruiken.

Conclusies

Zeker, awk is wellicht niet zo krachtig als andere hulpmiddelen die speciaal voor dit doel zijn ontworpen. Maar het heeft het grote voordeel dat je met een klein programmaatje snel een hulpmiddel kunt maken dat volledig de behoefte dekt.

AWK is zeer geschikt voor het doel waarvoor het gemaakt is: data regel voor regel inlezen en deze data bewerken naar gelang de inhoud en patronen van die regel.

Bestanden als /etc/passwd blijken ideaal voor bewerking met AWK. Het is hierbij onmisbaar.

Uiteraard is er meer dan alleen AWK. Perl is een geduchte concurrent, maar het is nog steeds nuttig om een paar awk-trucs te kennen.

Meer informatie

Dit soort basiscommando's is niet erg goed gedocumenteerd maar zoekt en gij zult vinden: Normaal gesproken wordt het commando door alle Unix boeken wel genoemd, maar slechts een klein deel gaat hier in detail op in. Het beste wat we kunnen doen is ieder boek doornemen waar we de hand op kunnen leggen, want je weet maar nooit waar je nuttige informatie vindt.