Onze geachte schrijver verkiest zijn publiekelijke leven met mysterie te omhullen. Vandaar dat hij anoniem blijft.
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.
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.
ls -1 *old* | awk '{print "mv "$1" "$1}' | sed s/old/new/2 | sh
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
ls -l | grep '^d' | awk '{print "rm -r "$9}' | sh
ls -p | grep /$ | wk '{print "rm -r "$1}'
)
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.
LaTeX
of, op zijn minst, in een
mooiere opmaak. Als het een eenvoudige tabel betreft (en/of we kennen
awk
heel goed) dan is het niet zo moeilijk.
BEGIN { printf "LaTeX preample" printf "\\begin{tabular}{|c|c|...|c|}" } |
{ printf $1" & " printf $2" & " . . . printf $n" \\\\ " printf "\\hline" } |
END { print "\\end{document}" } |
awk
gebruikt voor het opdelen van de grote
hoeveelheid uitvoer. Uiteraard moest ik hierbij gebruik maken van bepaalde
karakteristieken in de uitvoer.
|
( $1 == "====>" ) { NomObj = $2 TotObj = $4 if (TotObj > 0) { FS = "|" for (cont=0; cont<TotObj; cont++) { getline print $2 $4 $5 $3 >> NomObj } FS = " " } } |
Let op: in de praktijk werd de naam van het object niet geretourneerd en het lag allemaal wat gecompliceerder maar dit is dan ook slechts een voorbeeld ter illustratie. |
BEGIN { BEGIN_MSG = "From" BEGIN_BDY = "Precedence:" MAIN_KEY = "Subject:" VALIDATION = "[MONTH REPORT]" HEAD = "NO"; BODY = "NO"; PRINT="NO" OUT_FILE = "Month_Reports" } { if ($1 == BEGIN_MSG) { HEAD = "YES"; BODY = "NO"; PRINT="NO" } if ($1 == MAIN_KEY) { if ($2 == VALIDATION) { PRINT = "YES" $1 = ""; $2 = "" print "\n\n"$0"\n" > OUT_FILE } } if ($1 == BEGIN_BDY) { getline if ($0 == "") { HEAD = "NO"; BODY = "YES" } else { HEAD = "NO"; BODY = "NO"; PRINT="NO" } } if (BODY == "YES" && PRINT == "YES") { print $0 >> OUT_FILE } } |
Stel:we beheren een mailinglijst en af en toe
wordt er een speciaal bericht op de lijst gepost (een maandelijks overzicht
bijvoorbeeld) met een bepaalde vaste opmaak (het subject-veld
bijvoorbeeld als:
[MONTHREPORT} month, dept). Opeens besluiten we om een
eindejaarsoverzicht te maken met daarin een samenvatting van al de overzichten
(daarbij de rest negerend). Dat kan door de mail spool te bewerken met het awk
programma, zoals gegeven in de linkerkolom.
Om ieder overzicht in een apart bestand te krijgen moeten er drie extra regels code worden toegevoegd. |
Let op: dit voorbeeld gaat er vanuit dat de mail spool is opgezet zoals ik denk dat het is opgezet. Eigenlijk ken ik het echte formaat niet. Maar dit werkt op mijn machine (zoals altijd: in speciale gevallen zou het fout kunnen gaan). |
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. |
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.
awk
is niet voor iedere *nix hetzelfde, maar
er is een manier om er achter te komen op ons eigen systeem:man awk
gawk
richt. En nog zo'n half dozijn andere titels.