Awk on ohjelmointikieli, joka on erityisen tehokas käsiteltäessä järjesteltyä tietoa ja tulostettaessa raportteja. Awk voi lukea syötteen joko tiedostosta tai stdin:sta. Kuten sedkin awk lukee syötettä rivi kerrallaan. Syötteestä awk etsii rivit, jotka täsmäävät annettuun merkkijonolausekkeeseen ja suorittaa riveille halutut toimenpiteet.
Awkin käynnistys komentoriviltä tapahtuu seuraavasti:
awk [-v var=value] [-Ffs] 'program' file ...
tai
awk [-v var=value] [-Ffs] -f progfile file ...
Awk-ohjelman suorituksen voidaan ajatella koostuvan yhdestä ``syötesilmukasta''. Silmukassa luetaan rivi tiedostosta ja mahdollistetaan luetun rivin prosessointi. Tämä kaikki on awkssa sisäänrakennettuna, joten käyttäjän ei tarvitse huolehtia prosessoitavan tiedoston avaamisesta ja rivienlukemisesta. Normaalisti edellämainittua syötesilmukkaa suoritetaan niin kauan kun syötetiedostossa on rivejä.
Itse awk-ohjelma (program) koostuu yhdestä tai useammasta pattern- ja action-parista:
pattern {action} pattern {action} ...
Pattern-osa voi olla esim. merkkijonolauseke tai ehtolauseke, johon tietueen, yleensä rivin, sisältöä verrataan. Jos ehto tai lauseke täsmää, suoritetaan action-osan sisältämät komennot.
Esim.
awk '/^$/ {print "Empty line"}' file
Jos pattern-osa jätetään pois suoritetaan action-osan komennot kaikille tietueille.
Awk mahdollistaa myös tiettyjen rutiinien suorittamisen ennenkuin yhtään syöteriviä on luettu. Samoin awk mahdollistaa tiettyjen rutiinien suorittamisen, kun kaikki syöterivit on luettu. Kyseiset rutiinit määritellään awk-ohjelmassa BEGIN ja END avainsanoilla. Tällöin ohjelman rakenne voi olla seuraavanlainen.
BEGIN {action} pattern {action} pattern {action} ... END {action}
Awk olettaa, että syöte on jollain tavalla järjestettyä eikä vain päättymätön merkkijono. Perusoletuksena awkssa on että, syöte jakautuu tietueisiin (record) ja tietue jakautuu kenttiin (field). Tietueet erotellaan normaalisti rivinvaihdolla (rivit ovat siis tietueita) ja kentät joko välilyönneillä tai tabulaattoreilla. Kenttäerotin voidaan vaihtaa komentorivioptiolla -Ffs, missä fs tarkoittaa uutta kenttäerotinta.
Awkssa kenttiin voidaan viitata kenttäoperaattorilla $. Operaattoria seuraa numero tai muuttuja joka kertoo kentän paikan. $1 tarkoittaa ensimmaistä kenttää, $2 tarkoittaa toista kenttää jne.
Esim.
awk '{print $1, $3, $2}' tied
Tulostaa tiedoston tied riveiltä kentät yksi, kolme ja kaksi. $0 tarkoittaa koko syöteriviä.
Muuttujat awkssa voivat olla joko numero- tai merkkijonoarvoisia. Muuttujan tyyppiä ei määritellä erikseen vaan se määräytyy muuttujan arvon / sisällön perusteella. Muuttujia ei tarvitse alustaa erikseen, sillä kaikki awkssa esiintyvät omat muuttujat ovat oletusarvoisesti alustettu tyhjiksi numeroarvolla nolla.
Muuttujien nimet saavat sisältää sarjan kirjaimia, numeroita ja alaviivoja (_). Muuttujan nimi ei kuitenkaan saa alkaa numerolla. Isoilla ja pienillä kirjaimilla on oma merkityksensä eli a ja A ovat eri muuttujia.
awkssa on lisäksi joukko systeemimuuttujia, joilla on omat merkityksensä ja jotka ovat ns. ``varattuja nimiä''.
Awk tuntee joukon systeemimuuttujia (sisäisiä muuttujia). Nämä muuttujat voidaan jakaa kahteen tyyppiin. Ensimmäisen tyypin muuttujat ovat sellaisia joiden oletusarvoja on mahdollista muuttaa, tällaisia ovat esimerkiksi kenttä- ja tietue-erottimet. Toisen tyypin muuttujia käytetään lähinnä raporttien tulostuksessa ja prosessoinnissa. Näiden muuttujien arvot awk ylläpitää automaattisesti. Tällaisia muuttujia ovat esimerkiksi kenttien määrä nykyisellä rivillä sekä nykyisen rivin numero.
Tärkeimmät systeemimuuttujat:
Aritmeettiset operaattorit
Sijoitusoperaattorit
Boolen operaattorit
Vertailuoperaattorit
Tulostus awkssa tapahtuu print-komennolla, mutta print komento ei tarjoa mitään valmista keinoa tulostuksen formatointiin. Formatoituun tulostukseen käytetään C-kielestä lainattua printf funktiota, jonka syntaksi on
printf ( formaatti [, argumentit ])
Esim. 'BEGIN { printf ("Terve maailma!\n") }'
On muistettava että printf ei automaattisesti tulosta rivinvaihtoa kuten print. Printf funktiossa on rivinvaihto tulostettava erikseen käyttämällä ``\n'' merkintää.
Awk-kieli tarjoaa myös mahdollisuuden ehtorakenteiden ja silmukoiden käyttöön. Awkssa näiden rakenteiden syntaksi on lainattu C-kielestä.
Awkssa on kaksi ehtorakennetta, if ja C-kielestä tuttu
ehto-operaattori. If-lauseen syntaksi on seuraavanlainen:
if (ehto)
komento1
[else
komento2 ]
Jos ehto toteutuu (eli on eri kuin nolla tai ei-tyhjä), niin suoritetaan komento1. Mikäli else osa on määritelty komento2 suoritetaan jos ehto on epätosi (nolla tai tyhjä). Ehto voi sisältää aritmeettisia-, boolean- tai vertailuoperaattoreita. Mikäli komeentoja on useampia on ne sijoitettava kaarisulkuihin { }.
Esim. if ( x ) print x
Mikäli x:llä on nollasta poikkeava arvo se tulostetaan.
Toinen ehtorakenne on niinsanottu ehto-operaattori.
ehto ? toimenpide1 : toimenpide2
esimerkiksi seuraava rakenne:
if ( x > y ) string = "Suurempi" else string = "Pienempi"voitaisiin kirjoittaa lyhyemmin muotoon:
string = ( x > y ) ? "Suurempi" : "Pienempi"
Silmukka voidaan awkssa määritellä kolmella tavalla, käyttäen joko while-, do(-while)- tai for-rakennetta.
While-silmukan rakenne on seuraavanlainen:
while ( ehto )
komennot
Silmukan aluksi ehto tutkitaan ja mikäli se on tosi suoritetaan komennot. Mikäli ehto ei ole koskaan tosi ei silmukan runkoa koskaan suoriteta. Jos komentoja on useampia on ne suljettava kaarisulkuihin { }
i=1 while ( i <= 4 ) { print $i i++ }
Do-silmukka (tai do-while) on muunnelma while-silmukasta, ja sen rakenne on seuraavanlainen:
do
komennot
while ( ehto )
Do-silmukan ero while-silmukkaan on siinä, että tutkittava ehto on silmukan lopussa. Tämä aiheuttaa sen että silmukassa määritellyt komennot suoritetaan ainakin kerran. Kuten while-silmukassakin, kaarisulkuja { } on käytettävä, jos suoritettavia komentoja on useampia.
Kolmas awkn tuntema silmukka on for-silmukka. For-silmukan rakenne on:
for ( lask_alustus; lask_testaus; lask_kasvatus )
komennot
lask_alustus tarkoittaa laskuri muuttujan alustamista.
lask_testaus tarkoittaa laskuri muuttujan testausta silmukan alussa.
lask_kasvatus tarkoittaa laskuri muuttujan kasvatusta silmukan lopussa juuri ennen laskurin testausta lask_testaus.
for ( i = 1; i <= NF; i++ ) print $i
Taulukko on muuttuja, johon on mahdollista tallettaa joukko arvoja. Taulukossa oleviin arvoihin voidaan viitata taulukon indekseillä. Awkssa taulukon kokoa ei tarvitse määritellä - muuttujaa vain käytetään taulukkona. Taulukkoon sijoitetaan arvoja seuraavalla tavalla.
taulukko[indeksi] = arvo
Esim.
taulu[1] = "Maanantai"
Taulukon arvo voidaan tulostaa seuraavasti:
print taulu[1]
Awkssa kaikki taulukot ovat assosiatiivisia, mikä tarkoittaa, että taulukon indeksit voivat olla joko numeroita tai merkkijonoja.
Esim.
taulu[Ma] = "Maanantai"
print taulu[Ma]
For-silmukasta on olemassa on variantti assosiatiivisten taulukoiden käsittelyyn. Syntaksi on seuraavanlainen:
for ( muuttuja in taulukko )
tehdaan jotain taulukko[muuttuja]:lle
Avainsanaa in voidaan käyttää myös testattaessa löytyykö tietylle indeksille arvoa taulukosta.
Syntaksi:
indeksi in taulu
palauttaa ykkösen (1) jos taulu[indeksi] löytyy ja nollan (0) jos ei löydy.
Taulukon luomiseen voidaan käyttää awkn sisäistä funktiota split(). Split() funktion syntaksi on
n = split(jono, taulukko, erotin)
Missä jono on on merkkijono joka jaetaan taulukon taulukko elementeiksi. Jono jaetaan elementeiksi käyttäen erottimena erotinta. Erotin voi olla kokonainen merkkijonolauseke. Mikäli erotinta ei määritellä käytetään erottimena muuttujaa FS. Taulukon indeksointi alkaa ykkösestä (1) ja jatkuu n:ään.
Esim.
BEGIN { split (" Ma, Ti, Ke, To, Pe, La, Su", viikon_p, ",") for ( paiva in viikon_p ) print paiva, viikon_p[paiva] }
Taulukosta voidaan poistaa arvoja komennolla:
delete taulukko[indeksi]
Awk ei suoraan tue moniulotteisia taulukoita, mutta se tarjoaa tavan simuloida moniulotteisia taulukoita.
Esim.
{ for ( i=1; i <= NF; i++) tied_taul[NR, i] = $i suur_nf = ( NF > suur_nf ) ? NF : suur_nf } END { for (j=1; j <= NR; j++) { for (k=1; k <= suur_nf; k++) { printf("%s ", tied_taul[j, k]) } printf("\n") } printf("3. rivin 2. alkio on: %s \n", tied_taul[3,2]) }
Oletetaan että em. esimerkki on tiedostossa mdarray.awk, jolloin sitä voidaan käyttää seuraavasti:
awk [-Ffs] -f mdarray.awk file
mlarray.awk skripti muodostaa tiedostosta file 2-ulotteisen taulukon, käyttäen kenttäerottimena -F optiolla annettua fs merkkijonolauseketta. Muuttujaan suur_nf talletetaan suurin kenttien määrä. END osa tulostaa taulukon rivi kerrallaan.
Em. esimerkki ei luo ``aitoa'' moniulotteista taulukkoa, vaan siinä konvertoidaan indeksit jonoksi (esim ``3'' ja ``2''), jotka liitetään yhteen käyttäen erottimena systeemimuuttujaa SUBSEP (``indeksierotin'', oletuksena \034). Eli [3, 2] tarkoittaa oikeasti ``[3\0342]''.
Usein toistuvat ja pitkät komentorutiinit kannattaa määritellä omiksi funktioikseen. Funktion määrittely awkssa on seuraavanlainen.
function funktion_nimi (parametrilista) {
funktion komennot
}
Itse määritelty funktio voi sisältää return-lauseen:
return expr
Funktio voi palauttaa (nimessään) arvon käyttämällä expr-osaa. Ilman expr-osaa funktio palaa (ilman ennustettavaa arvoa) jatkamaan komentoja funktion kutsun jälkeen. Esim.
BEGIN{ a=1; b=2 print ynnaa(a,b) } function ynnaa(a,b) { return a+b }
Awk tarjoaa myös joukon sisäisiä funktiota. Nämä funktiot voidaan jakaa kahteen tyyppiin: aritmeettisiin- ja merkkijonofunktioihin.
Awkssa on yhdeksän aritmeettista funktiota, jotka on esitelty seuraavassa.
Awkn sisäiset merkkijonofunktiot.
Seuraavassa vielä pari muuta hyödyllistä funktiota.
Getline funktiota käytetään uuden syöterivin lukemiseen, sillä voidaan lukea paitsi tavallisesta syöte virrasta myös syöte tiedostosta tai putkesta. Getline funktion toimii samaan tapaan kuin awkn next komento. Molemmat lukevat seuraavan syöterivin, mutta next komento palauttaa ohjelman suorituksen skriptin alkuun, kun taasen getline lukee rivin muuttamatta suorituksen paikkaa.
Funktion getline mahdollisia palautusarvoja ovat:
Esimerkki käyttäjän syötteen lukemisesta:
BEGIN { printf ("Anna nimesi: ") getline < "-" print }
System() funktio suorittaa parametrinä annetun systeemikomennon. Suoritetun komennon tulostetta ei kuitenkaan voi käyttää ohjelmassa, vaan system funktio palauttaa suoritetun komennon palautusarvon. Ohjelma odottaa komennon suorituksen päättymisen ennenkuin suoritusta jatketaan.
Esimerkki system funktiosta:
BEGIN { if (system ("mkdir tmp") != 0 ) print "Komennon suoritus ei onnistunut" }
Close() funktiota voidaan käyttää avoimien tiedostojen ja putkien sulkemiseen. Syitä close() funktion käyttöön: Putkia voi olla avoinna vain tietty määrä samanaikaisesti, systeemi rajoittaa avoimien tiedostojen määrän jne.
Esimerkki putken sulkemisesta:
BEGIN { while ("who" | getline) who_out[++i] = $1 close("who") for ( kuka in who_out ) print who_out[kuka] }