Nykyinen versio |
Oma tekstisi |
Rivi 1: |
Rivi 1: |
| {{DISPLAYTITLE:{{lcfirst:{{PAGENAME}}}}}}
| |
| '''awk'''-työkalun avulla voi helposti muuntaa tekstitiedoston rakennetta. awk ja sen laajennettu versio gawk kuuluvat Unix/Linux-käyttäjän perustyökaluihin silloin, kun kyseessä on:
| |
| * puhtaan tekstitiedoston muuntaminen riveittäin toiseen muotoon
| |
| * rivien suodattaminen pois tekstistä tavalla, johon [[grep]] ei kykene
| |
| * laskujen laskeminen riveillä olevilla numeroilla
| |
|
| |
|
| == Johdanto ==
| |
| awk on skriptikieli ja samanniminen tulkki tälle skriptikielelle. Se on tarkoitettu tiedon hakemiseen selkeän rakenteen omaavista tekstitiedostoista ja tämän tiedon esittämiseen siistissä muodossa. Sen kehittäminen aloitettiin jo 1977 AT&T:n tutkimuslaboratoriossa (''[[Bell Labs]]''). Samassa paikassa aloitettiin muutama vuosi aikaisemmin myös [[Unix]]in kehittäminen.
| |
|
| |
| awk:n tilalla on monesti käytetty [[Perl]]iä, joka on kehitetty mm. ratkaisemaan samankaltaisia ongelmia kuin awk. awk:n opettelu ei silti ole turhaa, sillä:
| |
| *awk on yksinkertaisempi (tärkeää jos mietit, kumman opettelisit ensin)
| |
| *awk:n syntaksi on säännöllisempi
| |
| *awk löytyy lähestulkoon järjestelmästä kuin järjestelmästä, Perl-tulkki ei
| |
| *[http://pubs.opengroup.org/onlinepubs/009695399/utilities/awk.html IEEE:n Unix-standardi] määrittelee awk:n melko kattavasti, kun taas Perlin parametrit ja syntaksi ovat eläneet päätoteutuksen mukana
| |
|
| |
| Tärkeää on siis ymmärtää, että awk ei ole ainoa työkalu tietyntyyppisten ongelmien ratkaisemiseen. Eikä se ole myöskään monipuolisin. Se saattaa kuitenkin monissa tilanteissa olla yksinkertaisempi käyttää kuin Perl-skriptit.
| |
|
| |
| == Syntaksi ==
| |
| awk:n syntaksi on lähellä [[C]]:n syntaksia. Seuraavat asiat on kuitenkin syytä huomioida:
| |
| * muuttujilla ei ole tyyppiä ja muunnokset tehdään automaattisesti.
| |
| * taulukkoindekseinä voi käyttää periaatteessa mitä tahansa, tästä on paljon hyötyä niissä tehtävissä, joihin awk on ensisijaisesti tarkoitettu
| |
| * syöttödata pilkotaan automaattisesti $1..n numeroiduiksi kentiksi yleensä välilyönnin kohdalta.
| |
| * virheilmoitusten tulkinta voi olla hankalaa
| |
|
| |
| Yksinkertaisimmillaan awk:ta voidaan käyttää riveillä muotoa
| |
| lauseke {komento}
| |
| missä ''lauseke'' voi olla säännöllinen lauseke tai etsittävä merkkijono. Esimerkiksi rivi
| |
| /linux/ {print}
| |
| tulostaisi kaikki rivit, joilla esiintyy sana "linux".
| |
|
| |
| == awk-ohjelman käyttö ==
| |
| awk:ta käytetään komentoriviltä antamalla sille syötteenä skripti ja tiedosto, jota tällä skriptillä käsitellään. Skripti voidaan antaa joko komentoriviparametrina tai pidempien skriptien kanssa antamalla parametrina tiedosto, josta skripti ladataan. Eli joko
| |
| awk -f skripti.awk tiedosto.txt
| |
| tai
| |
| awk '/linux/ {print}' tiedosto.txt
| |
|
| |
| == Kenttien käsittely ==
| |
| awk:n vahvin puoli on sen kyky käsitellä tiedoston sisältöä kenttinä. Esimerkiksi voimme helposti tulostaa tekstitaulukosta jokaisen rivin kolmannet solut.
| |
|
| |
| Tutkitaan esimerkiksi tiedostoa [[Passwd-tiedosto|/etc/passwd]] josta löytyy tietokoneen käyttäjien käyttäjätunnukset. Tämä tiedosto on muotoa
| |
| <pre>
| |
| root:x:0:0:root:/root:/bin/bash
| |
| daemon:x:1:1:daemon:/usr/sbin:/bin/sh
| |
| bin:x:2:2:bin:/bin:/bin/sh
| |
| </pre>
| |
| Leikitään, että haluamme tulostaa tiedostosta käyttäjien nimet. Käyttäjätunnus on jokaisella rivillä ensimmäinen kenttä, jos kentät erotellaan :-merkillä. Tehdään tällainen awk-skripti.
| |
|
| |
| Määritellään ensin erotinmerkiksi kaksoispiste asettamalla se muuttujan FS komennolla
| |
| FS = ":"
| |
| Komentoriviltä käytettäessä tämä voitaisiin asettaa valitsimella -F:
| |
| awk -F ":" ....
| |
| Tämän jälkeen awk erottelee jokaiselta riviltä vuorotellen kaksoispisteen erottamat merkkijonot (kentät) muuttujiin $1, $2,... Esimerkiksi tässä tapauksessa ensimmäisellä rivillä $1 olisi "root" ja $2 olisi "x". Nyt voimme tulostaa jokaiselta riviltä ensimmäisen kentät komennolla <tt>print $1</tt>, eli lopullinen awk-skriptitiedosto olisi
| |
| FS = ":"
| |
| { print $1 }
| |
| Toisaalta tämä voitaisiin ajaa myös yhdellä komennolla:
| |
| awk -F : '{print $1}' /etc/passwd
| |
|
| |
| == BEGIN- ja END-lohkot ==
| |
| awk käsittelee syötteensä [[grep]]in ja [[sed]]in tavoin rivi kerrallaan. BEGIN- ja END-lohkoissa suoritetaan asiat, jotka on kuitenkin tarkoitus tehdä suoritusaikana vain kerran ennen ja jälkeen varsinaisen syötteen käsittelyä.
| |
| awk 'BEGIN {aluksi} lauseke1 {jokaiselle lauseke1:lle} \
| |
| lauseke2 ... END {lopuksi}' tiedosto
| |
|
| |
| == Ehtolauseet ja vertailut ==
| |
|
| |
| == Printf ==
| |
| Printf on awk:n funktio, jolla on mahdollista tehdä tarkempia muotoiluja tulostukselle. Se toimii samaan tapaan kuin vastaava funktio [[C]]-kielessä ja sen syntaksi on
| |
| printf "muotoilumerkkijono", muuttuja1, muuttuja2, ...
| |
| Ensimmäisenä annettava merkkijono sisältää tavallista tulostuvaa tekstiä ja voi lisäksi sisältää erikoismerkkejä, joiden paikalle sijoitetaan annettavat muuttujat sopivasti muotoiltuna. Ensimmäinen erikoismerkki käsittelee ensimmäisen parametrina annetun muuttujan, toinen toisen jne.
| |
|
| |
| Erikoismerkit alkavat prosenttimerkillä jota seuraa kirjain ja mahdollisesti numeroita (jos halutaan tulostaa prosenttimerkki, on käytettävä merkintää %%). Erikoismerkkejä ovat
| |
| {| border=1
| |
| |-
| |
| |'''Merkki'''
| |
| |'''Selitys'''
| |
| |-
| |
| |%c
| |
| |Tulostaa ASCII-numeroa vastaavan merkin. Esimerkiksi <tt>printf "%c", 65</tt> tulostaisi "A"
| |
| |-
| |
| |%d
| |
| |Tulostaa kokonaisluvun
| |
| |-
| |
| |%i
| |
| |Tulostaa kokonaisluvun
| |
| |-
| |
| |%e
| |
| |Tulostaa luvun halutussa eksponenttimuodossa. Esimerkiksi <tt>printf "%4.3e", 1950</tt> tulostaisi "1.950e+03" (4 merkitsevää numeroa ja eksponenttina 3)
| |
| |-
| |
| |%f
| |
| |Tulostaa desimaaliluvun
| |
| |-
| |
| |%g
| |
| |Tulostaa luvun joko desimaali- tai eksponenttimuodossa sen mukaan, kummassa tarvitaan vähemmän merkkejä
| |
| |-
| |
| |%o
| |
| |Tulostaa etumerkittömän oktaaliluvun
| |
| |-
| |
| |%s
| |
| |Tulostaa merkkijonon
| |
| |-
| |
| |%x
| |
| |Tulostaa etumerkittömän heksaluvun
| |
| |-
| |
| |%X
| |
| |Tulostaa etumerkittömän heksaluvun käyttäen desimaaliluvuille 10-15 isoja kirjaimia
| |
| |-
| |
| |}
| |
|
| |
| == Silmukat ==
| |
|
| |
| == Muuttujat ==
| |
| Shell-muuttujia voi välittää awk:lle luettelemalla ne parametreissa. Luvun 12 tulostus:
| |
| a=12
| |
| echo '\n' | awk -v a=$a 'END {print a}'
| |
|
| |
| {| border=1
| |
| |-
| |
| |'''Muuttuja'''
| |
| |'''Selitys'''
| |
| |-
| |
| |FNR
| |
| |Rivinumero tiedostossa, BEGIN-lohkossa 0.
| |
| |-
| |
| |FS
| |
| |Kentän erotin, vakiona <space>.
| |
| |-
| |
| |NF
| |
| |Kenttien lukumäärä rivissä, BEGIN-lohkossa määrittelemätön.
| |
| |-
| |
| |NR
| |
| |Rivinumero syötteessä kokonaisuutena, BEGIN-lohkossa 0.
| |
| |-
| |
| |OFMT
| |
| |Formaatti numeroille printf-komennossa, oletuksena "%.6g".
| |
| |-
| |
| |OFS
| |
| |print-komennon kenttäerotin, oletuksena <space>.
| |
| |-
| |
| |ORS
| |
| |print-komennon rivierotin, oletuksena <newline>.
| |
| |-
| |
| |RLENGTH
| |
| |match-funktion tuloksen pituus.
| |
| |-
| |
| |RS
| |
| |Rivierotin, vakiona <newline>.
| |
| |-
| |
| |RSTART
| |
| |match-funktion paluuarvo, eli merkkijonon ensimmäisen merkin sijainti rivillä.
| |
| |-
| |
| |}
| |
|
| |
| Muuttuja $0 viittaa kulloiseenkin riviin kokonaisuudessaan.
| |
|
| |
| {}-lohkojen sisällä voi määritellä muuttujia C-sukuisten kielten tavoin:
| |
| awk 'BEGIN {a=2} {if (NR % a == 0) print $0; else print "---"}'
| |
|
| |
| == Funktiot ==
| |
| {| border=1
| |
| |-
| |
| |'''Funktio'''
| |
| |'''Kuvaus'''
| |
| |-
| |
| |sub(ere, repl[, in ])
| |
| |Korvaa rivin ensimmäisen eren replillä.
| |
| |-
| |
| |gsub(ere, repl[, in ])
| |
| |Korvaa rivin kaikki eret repleillä.
| |
| |-
| |
| |length[([s])]
| |
| |Palauttaa parametrin tai koko rivin pituuden.
| |
| |-
| |
| |match(s, ere)
| |
| |Palauttaa eren alun paikan s:ssä.
| |
| |-
| |
| |split(s, a[, fs ])
| |
| |Paloittelee s:n a:han. fs oletuksena FS.
| |
| |-
| |
| |substr(s, m[, n ])
| |
| | -
| |
| |-
| |
| |tolower(s)
| |
| | -
| |
| |-
| |
| |toupper(s)
| |
| | -
| |
| |-
| |
| |close(exp)
| |
| | -
| |
| |-
| |
| |getline
| |
| |Siirtyy seuraavalle riville.
| |
| |-
| |
| |system(exp)
| |
| |Komento awk:n ulkopuolelle.
| |
| |}
| |
|
| |
| == Taulukot ==
| |
|
| |
| == Esimerkkejä ==
| |
|
| |
| Tiedostoa data.txt, jonka sisältö on seuraava:
| |
| 1 2 3
| |
| 4 5 6
| |
| 7 8 9
| |
|
| |
| käsitellään seuraavanlaisen awk-ohjelman avulla:
| |
| # tämä on awk ohjelma apu.awk
| |
| # tämä begin-lohko ajetaan aluksi kerran
| |
| BEGIN {
| |
| printf("alkutemput\n---------\n");
| |
| }
| |
| # Tässä välissä on varsinainen awk-ohjelmien 'äly'. Näitä lohkoja
| |
| # voi olla useita, ja niiden eteen voi laittaa ehdon, jolla ko. rivi ajetaan.
| |
| # Jos alla olevan lohkon alun muuttaisi $1 == 4 { niin lohko ajettaisiin
| |
| # vain riville joka alkaa numerolla 4. Ilman ehtoa se ajetaan kaikille riveille
| |
| {
| |
| printf "[%s] [%s] [%s] -> %d\n",$1,$2,$3,$1+$2+$3
| |
| }
| |
| # tämä end lohko ajetaan kerran lopuksi
| |
| END {
| |
| printf("---------\nlopputemput\n");
| |
| }
| |
|
| |
| Kun tiedosto data.txt syötetään ylläkuvatulle awk-ohjelmalle komennolla
| |
| awk -f apu.awk <data.txt>
| |
|
| |
| on tulos seuraava:
| |
| alkutemput
| |
| ----------
| |
| [1] [2] [3] -> 6
| |
| [4] [5] [6] -> 15
| |
| [7] [8] [9] -> 24
| |
| ----------
| |
| lopputemput
| |
|
| |
|
| |
| Seuraavalla komennolla etsitään pieniä, alle 100 merkin tiedostoja /etc-hakemistosta:
| |
| ls -l /etc |awk '$5 < 100 {printf "%6s %s\n",$5,$8}'
| |
|
| |
|
| |
| Poimitaan ja siistitään nykyinen resoluutio xrandr-komennon tulosteesta:
| |
| xrandr -q | awk 'NR==2 {sub(/\+.*\+.*/,"",$3; print $3}'
| |
|
| |
| == Muuta ==
| |
| awk:n on sanottu joskus olevan "write only language", ja sitä se onkin jos yrittää saada todella monimutkaisesta awk-ohjelmasta selkoa. Omat ohjelmat kannattaa tehdä siten, että kirjoittaa ja testaa ohjelman rivi kerrallaan. awk on parhaimmillaan lyhyissä muutaman rivin ohjelmissa.
| |
|
| |
| awk-ohjelmissa ei ole yleensä mitään rajoitusta käsiteltävien tiedostojen koolle, koska niitä käsitellään vain riveinä ja syöttö/tulostus putkina/virtoina. Awk-ohjelmat pystyvät käsittelemään varsin helposti hyvinkin suuria syöttö/tulostustiedostoja (satoja megatavuja).
| |
|
| |
| ==Aiheesta muualla==
| |
| *[http://www.unix.se/Awk Awk-artikkeli] unix.se-wikissä (ruotsiksi), josta tämä artikkeli on osittain käännetty. [[Keskustelu:Awk|Lisätietoja]].
| |
| *[http://www.cs.uu.nl/~piet/docs/nawk/nawk_toc.html awk-opas]
| |
| *[http://www.cs.utah.edu/dept/old/texinfo/gawk/gawk_toc.html Gawk-opas]
| |
| *[http://www.pement.org/awk/awk1line.txt Havainnollistavia yksirivisiä]
| |
|
| |
| [[Luokka:Komentorivin perustyökalut]]
| |