Awk:illa voi muodostaa pikavauhtia ohjelmia jotka ovat säällisen nopeitakin, sillä awk on vain kytkin joka suoritututtaa
kaiken toiminnan C-kielisisissä ohjelmissa. Tein pienen alkeis-oppaan yksirivisten awk:lauseiden käyttämisestä BASH-skriptissä:
- awk ei tee muutoksia editoitavaan, awk vain tulostaa.
- uudelleenohjaus kyllä toimii normaalisti, joten tiedostoon voi kirjoittaa. Uudelleenohjaus toimii samoin kuin BASH:issa. Siihen tiedostoon
josta lukee ei kuitenkaan voi kirjoittaa.
- käsiteltävät voidaan toimittaa awk:iin joko: awk .... TiedostonNimi tai: "tulostus jollain konstilla" | awk ....
Teoriassa ne ovat samanarvoisia keinoja, mutta tiedostoissa on usein monia rivejä jotka käsitellään awk:in rungossa mutta
kun syöte on ei-matriisi-muuttuja niin sitä käsitellään yleensä BEGIN osassa eikä muita osia ole. Awk muuten vaatii syötettä
silloinkin kun se ei tee syötteellä mitään.
- käskyjen muotoja tai tarkkaa kyky-luetteloa ei kannata opetella enempää kuin senverran että tietää mikä on mahdollista,
sillä ohjelmoitaessa käskyt kopioidaan esimerkki-varastosta eikä juuri mitään kirjoiteta.
- kovat lainausmerkit kuuluvat awk:iin ja esimerkiksi tulosteissa käytetään pehmeitä lainausmerkkejä ( kova on ' ja pehmeä " ).
____________________________________________________________________________________________________________________________
Jokaisessa awk-lauseessa on teoriassa kolme osaa:
1. BEGIN joka suoritetaan kerran alussa. Jos BEGIN osassa ei ole suoritettavaa niin sen voi jättää pois. Mikäli awk:issa tehdään
joku kertasuoritus, esimerkiksi lasketaan jotakin niin se suoritetaan BEGIN osassa ja muut osat jätetään pois.
2. Runko joka suoritetaan niin monta kertaa kuin käsiteltävässä on rivejä: siis awk:n runko on looppi jota ei täydy eikä voi
määritellä. Runko on se awk jota normaalisti käytetään ja nuo BEGIN ja END jätetään pois.
- rungon lauseet ovat tyypiltään: ehto-{toiminto} jossa toiminto suoritetaan mikäli ehto on tosi. Ehto-{toimintoja} voi olla
useampiakin kaksoispilkulla erotettuina. Mutta yhteen ehtoon tulee vain yksi toiminto; useampiakin toimintoja voidaan ehtoon
kyllä laittaa mutta ne täytyy silloin erottaa lohkoksi kaarisuluilla.
- awk lukee sisäänmenonsa rivi kerrallaan ja jakaa toimiessaan laittaa sen jokaisen rivin jokaisen sanan omaan muuttujaansa.
Näihin muuttujiin viitataan $1, $2, $3 ... . ja muuttuja $0 on koko lause. Siis kaikki ne vaihtuvat kun uutta lausetta
aletaan käsittelemään. Samoin awk määrittelee uudet arvot sisäisille muuttujilleen aina käsiteltävän lauseen muuttuessa:
FS, OFS, NF, NR, FNR, RS ja ORS
- FS mikä merkki jakaa sanat. Oletusarvo on välilyönti.
- OFS tämä arvo muuten asetetaan ohjelmassa ja se on se merkki joka jakaa sanoja tulosteessa, Oletusarvo on välilyönti
- NF kertoo montako sanaa on luettu.
- FNR kertoo kun on luettu monta tiedostoa mikä kussakin riviluku on
- RS kertoo mikä merkki jakaa lauseet sisääntulossa. Oletusarvo on rivinvaihto \n
- ORS kertoo millä merkillä tulostus-rivit jaetaan. Oletusarvo on rivinvaihto \n
- ellei muuta mainita niin sanojen erottimena FS toimii välilyönti, mutta erottimeksi voidaan asettaa miksi hyvänsä
käskyllä: -F<välimerkki>Hae
3. END joka suoritetaan kerran lopussa. Jos END osassa ei ole suoritettavaa niin sen voi jättää pois. Mutta jos END-osa on niin
runko-osa täytyy myös olla, vaikka pelkkä numero 0.
esimerkkejä BEGIN ja END-lohkojen käytöstä:
- awk 'BEGIN { print "koneessa olevien imageiden lukumäärä:"} /menuentry/{n++} END {print n}' /boot/grub/grub.cfg
- seq 21 | awk 'BEGIN {a=1; b=1} {b=b+1;a=a*b} END {print "kertoma: " a}' # huomio että seg 21 on matriisi
- awk 'BEGIN { while (count++<50) string=string "x"; print string }' # tulostaa 50 x:ää
- awk 'BEGIN{ count=1; do print "Tämä tulostuu ainakin kerran"; while(count!=1)}'
____________________________________________________________________________________________________________________________
- Awk olettaa paljon siitä mikä jätetään mainitsematta. Määrää siis tai awk olettaa !
Esimerkiksi käsky: awk 1 tiedosto tulostaa tiedoston sillä 1 on aina tosi ja print suoritetaan kun muutakaan ei määrätä.
Lauseessa ei myöskään ole mainintaa siitä mitä pitäisi tulostaa - mutta awk olettaa että haluat tulostaa käsittelyssä olevan
rivin jos et määrää toisin. Ja käsky: awk '{ print $1 }' tiedosto tulostaa tiedoston jokaisen rivin ensimmäisen kentän,
sillä koska ehtoa ei ole niin awk olettaa että jokainen rivi täyttää ehdon.
- Kaikki mikä tapahtuu awk:issa unohdetaan kun awk:in suoritus lopppuu. Awk ei pysty asettamaan BASH:in muuttujia eikä BASH
kykene asettamaan awk:in muuttujia. Mikäli haluaa käyttää awk:in muuttujia BASH:issa täytyy awk:n tulostaa ne ja BASH:in
napata muuttujien arvot konstilla: muuttuja=$(awk .....) ja awk:iin päin muuttujat siirretään putkittamalla ne.
Mutta awk kykenee käyttämään BASH:in muuttujia monellakin tavalla, esimerkiksi:
- koe=12345 ; awk 'BEGIN { print '"$koe"'; }' # tällä konstilla piisaa rajoituksia.
- arvo="4.58"; echo -n "" | awk -v arvo="$arvo" 'BEGIN { print arvo }'
- haettava="menuentry"; awk "/$haettava/ "'{ osumia++ } END { print "imageiden lukumäärä: " osumia }' /boot/grub/grub.cfg
- awk 'BEGIN { printf "Moikka %s" ,ENVIRON["USER"] }'
- export a="onnistuu se näinkin"; awk 'BEGIN { printf "%s" ,ENVIRON["a"] }'
- export tunnus=$(awk '/ Varaustunnus:/{print $2}' tiedosto); echo $tunnus
- awk:n sisäiset muuttujat: FS, OFS, NF, NR, FNR, RS ja ORS . Esimerkkejä:
- awk '{ if (NF > 0) printf("%s\n", $0); }' # tiedoston tyhjien rivien poistaminen
- awk 'NF { $0=++ a " : " $0 }; { print }' # tulostaa tiedoston rivien eteen: <rivinumero>:
- awk '{ total = total + NF } END { print total }' # tulostaa tiedoston sanojen lukumäärä.
- awk '{if (NR % 2 == 1) print $0}' # tulostaa vain parittomat rivit
- awk 'NR >= 3 && NR <= 6' # tulostaa rivit 3-6
- awk 'BEGIN { ORS="\n\n" }; 1' # tulostaa tiedoston rivien väliin tyhjän rivin
- awk '1; { print "" }' # sama toisella tavalla.
- awk 'BEGIN { FS=" ";OFS="#" } { if ($1==1) print $1,$2 }' ~/testResults.dat # tulostuu: 1#2 kun luettavassa on rivi 1 2
- print $1,$2 pitää olla pilkun kanssa; print yksinkin tulostaa kaiken, mutta välieroitin ei muutu - print $0 ei myöskään toimi
- awk 'END {print NR}' tiedosto # tulostaa tiedoston rivien lukumäärän
- awk '{if (NR % 2 == 1) print $0}' # tulostaa vain parittomat rivit
- awk -F : '{print $1}' /etc/passwd # tulostaa käyttäjien nimet (suurin osa on käyttöjärjestelmän ohjelmia)
- echo "1=2 3" | awk -F "=| " {'print $1, $2, $3'} # voidaan määrätä useampikin kentänjako |-funktiolla.
# Käskyssä {'print $1, $2, $3'} pilkut tulostavat OFS:n arvon.
- awk:in vertailuoperaattorit ovat: == , != , < , > , <= , >= , ?: ~ ja !~ Esimerkiksi:
- awk -F':' '$6 ~ /home/ && $3 >= 1000 { print $1 }' /etc/passwd # listaus tietokoneen käyttäjistä. Selväkielisenä tämä on:
Jaa tiedosto /etc/passwd kenttiin joiden rajana on merkki : . Kun kentässä 6 on osana sana home niin mikäli kentän 3 arvo
on yli 1000 niin tulosta kenttä 1.
- tuo ?: on ehdollinen ehto: ehto1 ? ehto2 : ehto3
Mikäli ehto2 on tosi toimitaan jatkossa ehto2:n mukaan mutta jos se ei ole tosi niin toimitaan ehto3:n mukaisesti.
- verrattavalla sanalla voi olla samanlaisia lisämääreitä kuin grep:illä: $ ^ . [....] [^....] | (....) * + ? /
- awk tuntemaa matematiikkaa: + ,-, *, /, %, välilyönti, **, int, log, sqrt, exp, atan2(m,n), sin, cos, tan, rand, srand
- luontaista suoritusjärjestystä voi muuttaa suluilla.
- matikka on kaksois-tarkkuutta (noin 22 numeroa)
- awk tuntee kokonaisluvut, desimaaliluvut, assosiatiiviset matriisit ja tekstijonot. Myös eksponentti-esitys tunnetaan.
- awk:in muuttujat ovat tyypittömiä. Operaatiot ++ ja -- tunnetaan. && on ja-toiminto, || on tai-toiminto ja ! on negaatio.
- Bitti-operaatioista tunnetaan and, or, xor, lshift, rshift ja compl. And, or ja xor voivat ottaa useampiakin lukuja.
- välilyöntioperaattori liittää yhteen eri puolillaann olevat. Siten 1+2*3 4; on arvoltaan 74. Esimerkkejä:
- awk '{sum+=$1; sumsq+=$1*$1} END {print sqrt(sumsq/NR - (sum/NR)^2)}' # ensimmäisen sarakkeen normaalipoikkeama
- awk 'BEGIN { print atan2(30,45); }' # palauttaa y/x arctangentin radiaaneissa.
- seq 21 | awk 'BEGIN {a=1; b=1} {b=b+1;a=a*b} END {print "kertoma: " a}' # kertoma. Huomio että seg 21 on matriisi
- merkkijonon käsittely-funktiot: index, length, match, split, sprintf, sub, gsub, substr, tolower, toupper . Esimerkiksi:
- echo ~/kansio1/kansio2/tämä muutetaan suurille | awk -F"/" '{ $NF=toupper($NF); print }' OFS="/"
- awk 'BEGIN {var = sprintf("[%8.3f]",3.141592654); print var}' # siis tämä on toiminto "printtaa stringiin"
- echo "kattokassinen" | awk '{gsub(/ka/,"ki");print}' # tulostaa: kittokissinen (gsub=global sub)
- awk '{ if (length($0) > max) max = length($0) } END { print max }' # tulostaa tiedoston pisimmän rivin pituuden
- awk '{print substr($0, index($0,$N))}' # tulosta N-palasesta eteenpäin
- awk 'length($0)!=12 {print}' your_file_name # tulosta rivit jotka eivät ole 12 merkkiä pitkiä
- awk -F':' '{split($0,a,":"); for (i=1; i<=NF; i++) if (a[i]) print i," ",a[i]}' /etc/passwd
- siis splitin jakaja ei määrää awk:in jakajaa
- I/O:n käsittely-funktiot: close, system
- awk tuntee myös ehtolauseet if, if-then ja if-else-then. Awk tuntee myös rakenteen ?: joka on itseasiassa if-else rakenne.
- esimerkkejä:
- awk '{ if (NF > 0) printf("%s\n", $0); }' # tiedoston tulostaminen tyhjät rivit poistettuina
- awk '{if (NR % 2 == 0) print $0; else print "pariton rivi"}' # tulostaa sanan pariton tai rivit jotka ovat parillisia.
- awk tuntee myos kierroslaskurin. Tunnetaan for, until, while ja do....while loopit. Myös break, continue ja exit tunnetaan.
Kierroslaskurin arvoksi jää sen viimeinen arvo kun kierrokset on tehty tai viimeinen arvo ennen break ja continue lauseita.
Esimerkkejä:
- awk '{ for (i = 0; i <= NF; i++); { printf "("%s ", i);}; printf("\n"); }' # rivien sanojen luku
awk tuntee printf:n muotoiluineen ja sen voi kirjoittaa print:in paikalle aina. Muotoilu-määreet ovat:
%c Tulostaa ASCII-numeroa vastaavan merkin. Esimerkiksi awk 'BEGIN {printf "%c", 65}' tulostaa "A"
%d Tulostaa kokonaisluvun
%i Tulostaa kokonaisluvun
%e Tulostaa luvun halutussa eksponenttimuodossa. Esimerkiksi printf "%4.3e", 1950 tulostaa: 1.950e+03
%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
- print tulostaa ilmanmuuta tulostettavan perään rivinvaihdon mutta printf ei
awk tuntee muuttujan ARGV jonka jäsen ARGV[1] on luetun tiedoston täysi nimi. Siitä esimerkki ja muutakin kokeilua:
Tiedostossa ~/taulukko on teksti:
1 2 3
4 5 6
7 8 9
- ja tarkoituksena olisi tulostaa taulukon arvot sekä sarake- ja rivisummat, muotoilla senverran että siitä saa selvää ja tulostaa
mistä tiedostosta arvot ovat:
awk 'BEGIN {print "arvot ovat tiedostosta: "ARGV[1]}; {rivisumma1+=$1;rivisumma2+=$2;rivisumma3+=$3;printf "%s %s %s sarakesumma=
%d\n",$1,$2,$3,$1+$2+$3} END {printf "%s %d %d %d %s","\nrivisummat:\n",rivisumma1,rivisumma2,rivisumma3,"\n\n"}' ~/taulukko
Sekalaista:
awk '/foo/' # tulostaa rivit joilta löytyy foo
awk '/kortti/,EOF' # tulosta tiedosto riviltä jossa on jossakin sana kortti loppuun asti
awk '/foo/ && /bar/' # tulostaa rivit joilta löytyy foo tai bar jossain järjestyksessä
awk '/foo/ && !/bar/' # tulostaa rivit joilta löytyy bar mutta ei foo
awk '/foo/ || /bar/' # tulostaa rivit joilta löytyy joko bar tai foo
awk '/foo/,/bar/' # tulostaa rivit riviltä jolta löytyy foo riville jolta löytyy bar.
awk 'BEGIN { print strftime() }' # tulostaa saman kuin BASH:in date
awk 'BEGIN { print systime() }' # tulostaa sekunnit siitä unixin alkuhetkestä
awk '{printf("%d\n",$1 + 0.5)}' # pyöristys; toimii sekä positiivisilla- että negatiivisilla luvuilla
awk '{if ($1 % 2 == 0) print $1 " on parillinen" ;else print $1 " on pariton"}'
awk '{$1=""; print}' # tulosta kaikki muu paitsi sarake 1
awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' # poistaa ByteOrderMark:in; esimerkiksi notepad lisää sen.
# Käsky ei tee mitään jos BOM:ia ei ole. Tämä BOM on UTF-8:ssa
awk '!($0 in array) { array[$0]; print }' # tulostaa tiedoston, mutta samanlaisista riveistä vain ensimmäisen
awk '!a[$0]++' # sama toisella tavalla
awk osaa lukea näppäimiäkin:
awk 'BEGIN {print "kerropa ikäsi:"; getline ika < "-"; print "ensi vuonna olet: " ika + 1 }'
- tuntee awk funktiotkin, mutta ne kuuluvat varsinaiseen awk-skriptiin, ei tämmöiseen yksiriviseen. Toiminta kuten BASHissa.
- BASH:in funktioitakin voi käyttää, mutta epäluotettava viritys tämä on:
echo -n "jotakin" | awk '{ tmp="echo -n " $1 " | openssl md5"; tmp | getline a; print a}'