Awk
Sisukord
- 1 Awk
- 2 Programmeerimise mudel
- 3 Awki käivitamine
- 4 Muutuja ja avaldis
- 5 Sisseehitatud käsud ja funktsioonid
- 6 Valikulause ja tingimused
- 7 if-else
- 8 Korduslause
- 9 While kordus
- 10 Do kordus
- 11 For kordus
- 12 Massiiv ja paisktabel
- 13 Paisktabel
- 14 Sisendi ja väljundi kasutamine
- 15 Faili lugemine ja kirjutamine
- 16 Süsteemi programmi väljundi lugemine ja sisendisse saatmine
- 17 Kirje ja väli
- 18 Kirje- ja väljaeraldusmärkide ümbermuutmine
- 19 Aadresseerimine
- 20 Funktsiooni defineerimine
Awk
Skriptkeel Awk on loodud tekstiliste andmetega manipuleerimiseks. Nimi Awk on akronüüm autorite perekonnanimedest - Aho, Weinberger, Kernighan. Segadust tekitav on paljude Awki versioonide levik, mis erinevad põhiliselt regulaaravaldiste tõlgendamisvõime poolest. Käesolev tegeleb GNU Awki versiooniga, mis muuhulgas tähendab seda, et saab kasutada laiendatud metasümbolite hulka (ingl. k. extended metacharacter set).
Programmeerimise mudel
Awk on sisendi poolt juhitav, mis tähendab, et tööosas näidatud käske rakendatakse vaikimisi Awki sisendisse suunatud andmete igale reale. Vaikimisi käsitleb Awk reana kahe järjestikulise '\n' -i vahele jäävat teksti. Awki skript võib koosneda kolmest osast:
ALGUSOSA - vastavad käsud täidetakse üks kord kõige alguses TÖÖOSA - vastavad käsud rakendatakse järjekorras igale sisendi reale LÕPUOSA - vastavad käsud täidetakse üks kord kõige lõpus
Neid osi märgitakse Awki skriptis selliselt, käsud kirjutatakse loogade vahele
BEGIN { algusosa käsud } { tööosa käsud } END { lõpuosa käsud }
Awkilik Awki kasutamine toimub rõhuasetusega tööosale. Järgnevas kirjeldame esituse selguse huvides keele vahendite süntaksit algusosa abil.
Awki käivitamine
Awki käske saab anda käsurealt või koondades nad ühte faili. Sellist käivitamisõigusega tekstifaili nimetatakse Awki skriptiks. Awki kasutamisel on võimalik tarvitada IO ümbersuunamist.
Toome näite, kuidas kahes tulbas ja tühikutega eraldatud sisendandmetel tulpade järjekord ära vahetada.
Olgu selline algtekst
bash~$ cat nimed Miima 1959 Priit 1963 Mart 1940 Peeter 1988
Käsurealt toimub tulpade vahetamine selliselt
bash~$ cat nimed | awk '{ print $2, $1 }' 1959 Miima 1963 Priit 1940 Mart 1988 Peeter
Awki skripti, mis vahetab tulbad, on selline
#!/usr/bin/awk -f { print $2, $1 }
Skript sisaldab vaid tööosa ja käivitatakse näiteks nii
bash~$ cat nimed | vaheta.tulbad.awk
Samaväärne oleks jätta skriptist esimene interpretaatorit näitev rida ära ja käivitada Awk selliselt
bash~$ awk -f vaheta.tulbad.awk nimed
Heaks kombeks on lõpetada skripti nimi viitega interpretaatorile.
Muutuja ja avaldis
Awkis ei ole vaja muutujaid enne kasutamist deklareerida ning puuduvad muutuja tüübid. Sõltuvalt kontekstist käsitletakse muutujat kas stringi või arvuna. Muutuja nimi peab algama tähega ja võib sisaldada peale tähtede ka numbreid ja alakriipse.
Toome näite muutujate kasutamisest
#!/usr/bin/awk -f BEGIN { x = 15 y = 2 w = "Tartu" z = "linn" x_korda_y = x * y print x " x " y " = " x_korda_y tartu_linn = w z print w " ja " z " on " tartu_linn }
* skript sisaldab vaid algusosa * defineeritakse neli muutujat: x, y, w, z * sooritatakse tehe arvudega ja stringidega ning trükitakse vastavad tulemused
Sisseehitatud käsud ja funktsioonid
Käsku print me oleme juba tarvitanud. Tema järgi kirjutatakse jutumärkidesse teksti ja ilma jutumärkideta muutujad, näites nimi ja x
print "Teie nimi on " nimi "ja te olete " x " aastat vana."
Tihti on otstarbekam kasutada käsku printf, mis sarnaselt C samanimelisele funtsioonile võimaldab väljundit paindlikumalt formateerida. Trükime ekraanile tehte 5/3 tulemuse nelja kohalisena, millest kaks on peale koma.
#!/usr/bin/awk -f BEGIN { a=5/3 printf ("%4.2f\n", a); }
Lisaks on olemas sellised sisseehitatud funktsioonid
* cos(x) - tagastab radiaanides esitatud argumendi koosinuse * sin(x) - tagastab radiaanides esitatud argumendi siinuse * atan2(x) - tagastab radiaanides esitatud argumendi arkustangensi * int(x) - tagastab argumendi täisosa * log(x) - võtab argumendist naturaallogaritmi * sqrt(x) - tagastab argumendi ruutjuure * rand(x) - genereerib juhusliku arvu vahemikus 0 kuni 1 * srand(x) - tekitab rand() funktsioonile juhusliku alge
Valikulause ja tingimused
if-else
Toome näite valikulausest, kus skript genereerib juhusliku arvu ja teatab, milline see arv on
#!/usr/bin/awk -f BEGIN { srand() x = rand () if ( x < 0.5 ) { print x " on vaiksem poolest" } else { print x " on yle poole" } }
Tingimusi seatakse võrdlustehte abil:
* < - väiksem * > - suurem * = - võrdne * != - mittevõrdne * <= - väiksemvõrdne * >= - suuremvõrdne
Võrdlustehete tulemustega saab sooritada loogilisi tehteid:
* ! - eitus * && - ja * || - või
Näiteks kirjutame skripti, mis ütleb, kas juhuslik arv on 0.2 < x < 0.8
#!/usr/bin/awk -f BEGIN { srand() x = rand () if ( x > 0.2 && x < 0.8 ) print " 0.2 < " x " < 0.8" }
Kui tingimusele järgneb vaid üks käsk, siis võib loogad ära jätta ja isegi kirjutada käsu tingimuse järele samale reale.
Võimalik on ka kasutada tuntud
(tingimus) ? (lause 1) : (lause 2)
sarnast konstruktsiooni.
#!/usr/bin/awk -f BEGIN { srand() x = rand () print ( x < 0.5) ? x " on vaiksem poolest" : x " on yle poole" }
Korduslause
Kordus sooritab tegevust mitu korda. Kõik näited väljastavad arvud ühest viieni.
While kordus
#!/usr/bin/awk -f BEGIN { x=1 while ( x <= 5 ) { print x x++ } }
Do kordus
#!/usr/bin/awk -f BEGIN { x=1 do { print x x++ } while ( x <= 5 ) }
For kordus
#!/usr/bin/awk -f BEGIN { for (x=1; x <= 5; x++) { print x } }
Massiiv ja paisktabel
Massiivi on otstarbekas kasutada, kui on vaja tegelda paljude samalaadiliste väärtustega.
Näiteks defineerimine massiivi m ja trükime korduse abil välja tema kõigi elementide väärtused:
#!/usr/bin/awk -f BEGIN { i=0 m[0] = "mina" m[1] = "sina" m[2] = "tema" while ( i < 3 ) { print m[i] } }
Paisktabel
Paisktabel on massiiv, mille indeksiks on string. Defineerime massiivi ja trükime välja teise elemendi.
#!/usr/bin/awk -f BEGIN { m["meie"] = "mina" m["teie"] = "sina" m["nemad"] = "tema" print m["teie"] }
Sisendi ja väljundi kasutamine
Skript loeb ootab andmeid sisendisse või klaviatuurilt ning kirjutab väljundisse või ekraanile.
#!/usr/bin/awk -f BEGIN { print "sisestage oma eesnimi" getline enimi < "-" print "sisestage oma perekonnanimi" getline pnimi < "-" print ( enimi == pnimi) ? "Teie ees- ja perekonnannimi on ühesugused"\ : "Teie ees- ja perekonnanimi ei ole ühesugused" }
Rida jätkav kaigas peab olema viimane sümbol real.
Eeldades, et tekstifailis on kahel real vastavalt eesnimi ja perekonnanimi, käivitatakse skript selliselt
bash~$ cat tekst | skript.awk
Soovides skripti tööosa kasutada, tuleb kirjutada selline skript, kusjuures andmefailis on ühel real tühikuga eraldatud ees- ja perekonnanimi.
#!/usr/bin/awk -f { print ( $1 == $2 ) ? "Teie ees- ja perekonnannimi on ühesugused"\ : "Teie ees- ja perekonnanimi ei ole ühesugused" }
Kui andmetega ridu on mitu, teostatakse kontroll iga reaga.
Faili lugemine ja kirjutamine
Loeme failist andmed ja kirjutame nummerdatud read teise faili.
#!/usr/bin/awk -f BEGIN { i=1 while ( (getline rida < "lahteandmed" ) > 0 ) { print i ". " rida > "toodeldudandmed" i++ } }
Korduse tingimuseks olev käsu getline lõppkood on nullist suurem seni kuni midagi failist lahteandmed lugeda on.
Süsteemi programmi väljundi lugemine ja sisendisse saatmine
Omistame muutuja aeg väärtuseks programmi date väljundi ning saadame muutuja aeg väärtuse programmi cat sisendisse.
#!/usr/bin/awk -f BEGIN { "date" | getline aeg print "Süsteemi aeg on " aeg print aeg | "cat" }
Kirje ja väli
Awk käsitleb sisendit struktureerituna. Vaikimisi nimetakse kahe järjestikuse reavahetuste vahele jäävat kirjeks. Vaikimisi on jaotatud rida väljadeks tühikute või tabulatsioonimärkide kohalt.
Programmi tööosas saab väljade poole saab pöörduda muutujate $1, $2, $3, $4 jne abil. Muutuja $0 väärtuseks on terve kirje.
Sõltuvalt välja sisust saab teha nendega tehteid. Toome näite, kus leiame tulpadena esitatud lähteandmete ridade summad
bash~$ cat arvud 1 3 4 5 4 6 2 4 1 5 9 4 2 4 5 5
ning skript leia.summad.awk on seesugune
#!/usr/bin/awk -f BEGIN { print "Leidame ridade- ja kogusumma" } { summa = $1 + $2 + $3 + $4 print $1 " + " $2 " + " $3 " + " $4 " = " summa kogusumma = kogusumma + summa } END { print "Kogusumma = " kogusumma }
Siin on esitatud kolm võimalikku skripti osa: algusosa, tööosa ja lõpuosa, kusjuures neile osadele vastavad käsud kirjutatakse loogadesse. Ühes osas kasutatud muutajatel on teises osas sama väärtus (nt kogusumma).
Käivitame skripti:
bash~$ cat arvud | leia.summad.awk Leiame ridade -ja kogusumma 1 + 3 + 4 + 5 = 13 4 + 6 + 2 + 4 = 16 1 + 5 + 9 + 4 = 19 2 + 4 + 5 + 5 = 16 Kogusumma on 64
Kirje- ja väljaeraldusmärkide ümbermuutmine
Mõnel juhul on vajalik andmeid ridadeks ja väljadeks jagavaid märke muuta. Vastavalt saab muuta ka väljundis kasutatavaid rea- ja väljaeraldusmärke.
Seda saab teha näiteks defineerides skripti algusosas üle vastavate muutujate väärtused:
* FS - sisendi välja eraldaja (ingl. k. field separator) * RS - sisendi kirje eraldaja (ingl. k. record separator) * OFS - väljundi välja eraldaja (ingl. k. output field separator) * ORS - väljundi kirje eraldaja (ingl. k. output record separator)
Kui välja eraldajaks on tühik, siis vastab see Awki vaikimisi toimimisele; sarnaselt on reavahetuse märgi ja kirje eraldajaga. Seades eraldajaks mõne teise sümboli, eraldatakse kirjet või välja selle sümboli kohalt. Kui eraldajaks on enam kui üks sümbol, käsitletakse eraldajat regulaaravaldisena.
Lisaks saab kasutada Awkiga seotud muutujaid
* FILENAME - sisendfaili nimi * NF - käesoleva kirje väljade arv (ingl. k. number on fields) * NR - kirje absoluutne järjekorra number (ingl. k. number of the record) * FNR - kirje suhteline järjekorra number; on vajalik mitme sisendfaili kasutamisel
Toome näite nende muutujate kasutamise kohta. Algandmed on sellised
Priit Elva Jüri 15 tel. 15 123 Mart Jüri Elva 15 tel. 12 3 15 Peeter Tartu Telefoni 5 tel. 12 34 56
Nad soovitakse esitada nii, et ühte linna puutuv oleks ühel real, read oleks nummerdatud ning kõige lõppu kirjutataks algandmete faili nimi
1:Priit:Elva:Jüri 15:tel. 15 123 2:Mart:Jüri:Elva 15:tel. 12 3 15 3:Peeter:Tartu:Telefoni 5:tel. 12 34 56 andmefail: andmed
Sellise töö teeb ära selline skript
#!/usr/bin/awk -f BEGIN {FS="\n"; RS="\n\n"; OFS=":"; ORS="\n"} { print NR, $1, $2, $3, $4 } END { OFS=" "; print "andmefail:", FILENAME }
Aadresseerimine
Regulaaravaldistega saab määrata, millistele sisendi ridadele tööosa käsud rakenduvad. Toome näite, kus tegeldakse vaid Tartu linna temperatuuride keskmistamisega. Algandmed failis temperatuurid on sellised
linn kp 6:00 12:00 18:00 24:00 Tartu 19/4/2000 13.6 15.1 15.8 14.0 Valga 19/4/2000 11.6 12.1 12.8 11.0 Tartu 20/4/2000 14.6 18.4 13.5 13.3 Valga 20/4/2000 13.4 15.7 15.1 14.3 Tartu 21/4/2000 16.6 21.1 19.3 17.1 Valga 21/4/2000 15.7 19.4 17.6 15.5 Tartu 22/4/2000 15.6 23.6 22.6 15.4 Valga 22/4/2000 13.5 16.2 14.7 15.3 Tartu 23/4/2000 17.3 19.4 21.4 12.3 Valga 23/4/2000 18.2 16.9 13.8 15.2
Skripti tööosa tegeleb vaid nende andmeridadega, mis klapivad regulaaravaldisega /Tartu/
#!/usr/bin/awk -f BEGIN { print "Tartu õhutemperatuuri ööpäevane keskmine" printf ("Teostati neli mõõtmist: 6:00 12:00 18:00 24:00\n\n") print "koht kuupäev mõõtmistulemus" } /Tartu/ { keskmine = ( $3 + $4 + $5 + $6 ) / 4 printf ("%s %s %2.2f\n", $1, $2, keskmine) } END { printf ("\nMõõtmisi teostasid Priit ja Mart\n") }
Käivitamisel saame järgmise tulemuse
bash$ cat temperatuurid | tartu.keskm.temp.awk Tartu õhutemperatuuri ööpäevane keskmine Teostati neli mõõtmist: 6:00 12:00 18:00 24:00 koht kuupäev mõõtmistulemus Tartu 19/4/2000 14.62 Tartu 20/4/2000 14.95 Tartu 21/4/2000 18.52 Tartu 22/4/2000 19.30 Tartu 23/4/2000 17.60 Mõõtmisi teostasid Priit ja Mart
Funktsiooni defineerimine
Funktsioonid defineeritakse väljaspool skripti osasid sellise süntaksi alusel
function funktsiooni.nimi (arg1, arg2, arg3) { laused return res1 res2 }
Esitame eelmise punkti viimase näite nii, et keskmine temperatuur leitakse funktsiooni abil
#!/usr/bin/awk -f BEGIN { print "Tartu õhutemperatuuri ööpäevane keskmine" printf ("Teostati neli mõõtmist: 6:00 12:00 18:00 24:00\n\n") print "koht kuupäev mõõtmistulemus" } function kesktemp (m1, m2, m3, m4) { keskmine = ( m1 + m2 + m3 + m4 ) / 4 return keskmine } /Tartu/ { printf ("%s %s %2.2f\n", $1, $2, kesktemp($3, $4, $5, $6)) } END { printf ("\nMõõtmisi teostasid Priit ja Mart\n") }
© EENet 2000