awk
Az awk egy olyan programozási nyelv, amit szöveges állományok feldolgozására terveztek. Egy tipikus awk programot (szkript) egy interpreter olvas be és hajt végre. A szkript végrehajtása során a feldolgozott szöveges állomány(ok)at (tartalmának változatlanul hagyásával) másféle kimenetté formálja át.
A bemeneti adatok változatlanul hagyása biztosítja, hogy ugyanazon adatokra (például szövegfájlok) többféle awk program is futtatható egymás után, vagyis ugyanazon fájl(ok)ból többféle adat is kinyerhető legyen.
Története
[szerkesztés]Elnevezése a megalkotói – Alfred Aho, Peter Weinberger és Brian Kernighan – családneveinek kezdőbetűiből született. Az eredeti awk az 1977-ben az AT&T Bell laboratóriumában készült. Ideális szöveges állományok szűrésére, átformálására és kiértékelésére. Ma is minden Unix rendszeren van legalább egy awk változat. A Free Software Foundation a gawk nevű változatot gondozza, a Linux disztribúciókkal is jellemzően a gawk implementációt szállítják. Windows rendszerekhez is letölthető a gawk például a Cygwin részeként. Elérhető MS-DOS, Atari és Amiga operációs rendszerek alatt is. Megszületése óta számos bővítése létezik, például QTAwk,[1] Xgawk (awk xml), Jawk (Java alapú)[2] stb. Az awk nyelv ereje, rövidsége, de az awk szkriptek határainak felismerése adta Larry Wallnak az ötletet a Perl nyelv kifejlesztésére. A futási sebesség növelése miatt kísérletek történtek awk programok fordítására is, azonban az eltérő utasításkészlet miatt például csak a tawk-szkript fordítható le futtatható kóddá.[3]
Egy awk program működése
[szerkesztés]Egy awk szkript futtatásához szükség van egy awk nyelvet feldolgozó (gawk, nawk stb.) interpreterre, a megfelelő szövegállomány(ok)ra és többnyire egy szkriptre, amely a tevékenységeket írja le. A nyelv tömörsége miatt néhány program olyan rövid, hogy parancssori paraméterként is beadható az interpreter részére.[4] Alapértelmezés szerint az interpreter a szabványos bemenetről olvassa a feldolgozandó adatokat (stdin) és az eredményeket a szabványos kimenetre írja (stdout), azonban átirányításokkal a működése kiterjeszthető.
Az awk adatvezérelt nyelv: minták és tevékenységek sorozatából áll. Beolvas egy sort, automatikusan mezőkre (szavakra) darabolja és a megadott feltételek szerint elvégzi a minta egyezőségének vizsgálatát. Ha van egyezés, akkor a mintához tartozó egy vagy több tevékenységet hajtja végre, majd a szabványos kimenetre írja. Ezután a következő sor feldolgozása történik a fentiek szerint, míg csak a fájl végére nem ér.
Egy awk program részei
[szerkesztés]Egy awk program a következő részekből állhat:
- előkészítő rész;
- saját függvénydefiníciók;
- programtörzs;
- befejező rész.
Fenti részekből a program sajátosságai szerint tetszőleges részek elhagyhatóak, ha az adott program nem igényli (például nincs előkészítésre szükség vagy nincsenek saját függvények, stb.).
Előkészítő rész
[szerkesztés]Jellemzően értékadó, vagy programfutást előkészítő parancsok találhatók ebben a részben.
BEGIN { parancsok }
#Adatbeolvasás előtt BEGIN kapcsos zárójelei közötti parancsokat hajtja végre.
#A BEGIN speciális mintaként is értelmezhető.
Saját függvénydefiníciók
[szerkesztés]A programok szerkesztését, futtatását megkönnyíti, ha a felhasználó új utasításokat hozhat létre a meglévő nyelvi elemek felhasználásával.
Programtörzs
[szerkesztés]A legegyszerűbb awk programok csak a programtörzset tartalmazzák és általában mintából és a mintához tartozó parancsokból, más néven tevékenységből állnak:
/1. minta/ { parancsok }
/2. minta/ { parancsok }
/minta/
# Ha nincs külön parancs megadva, a mintának megfelelő sort kinyomtatja a standard outputra.
{ tevékenységek }
# Ha nincs minta megadva, a tevékenységeket minden sorra egymás után végrehajtja.
Az awk soronként olvassa a bemenetet, ezért az awk program működéséhez kis operatív memória is elegendő. Minden beolvasott sort összehasonlít a mintákkal, és abban az esetben, ha illeszkedést talál, a mintához tartozó parancsokat végrehajtja. A mintákat a szabályos kifejezések szabályai szerint fejti ki, vagyis a minták reguláris kifejezéseket is tartalmazhatnak.
Befejező rész
[szerkesztés]Az összes adat feldolgozása és a többi parancs végrehajtása után a befejező rész parancsait hajtja végre. Jellemzően összegző- és formázó utasítások találhatók ebben a részben. Az END
speciális mintaként is értelmezhető.
END {tevékenységek}
Jelkészlet
[szerkesztés]Egy awk program nyelvi elemei az angol abc kis- és nagybetűit, számokat, írásjeleket és az aláhúzásjelet tartalmazhatják. A kis- és nagybetűvel jelölt azonosítók különbözőek.
Nyelvi elemek
[szerkesztés]Az awk számos nyelvi elemet használ a programozás megkönnyítésére, így például:
- változók,
- rekordok és mezők,
- tömbök,
- minták,
- tevékenységek,
- operátorok,
- vezérlő utasítások,
- be- és kimeneti utasítások,
- belső függvények,
- saját függvények.
- konstansok.
Változók
[szerkesztés]Egy awk szkript változói lehetnek
- felhasználó által létrehozott változók és
- előre definiált (belső) változók.
Az awk változói globális változók és azáltal jönnek létre, hogy használni kezdik őket, tehát dinamikus változók. A változók értéke lehet sztring vagy lebegőpontos szám, a használat módjától függően. Léteznek lokális változók is, amelyek csak az adott saját függvényen belül láthatóak, ezeket a függvény paraméterlistája után kell felsorolni.[5]
Belső változók
A belső változók mindig globálisak és a program működését befolyásolják. Megállapodás szerint a belső változókat mindig nagybetűkkel jelölik. Példák belső változókra:
- NR (Number of Records) A beolvasott rekordok (sorok) számát tartja nyilván.
- NF (Number of Fields) A beolvasott és feldolgozás alatt lévő rekord (sor) mezőinek (szavainak száma) Az utolsó mező a $NF.
- FILENAME A feldolgozás alatt álló fájl neve.
- FS (Field Separator) A mezőelválasztó karaktert tartalmazza, amely mentén az awk elvégzi a $0 tartalmának darabolását, alapértelmezés szerint a szóköz és a tabulátor jele. FS ="," hatására a mezők szétvágása nem szóközök mentén történik, hanem a vesszőkig (például CDF-formátum feldolgozása). A beolvasott rekord mezőelválasztó karakterei nem kerülnek feldolgozásra és tárolásra, csupán egy jelzés a feldolgozónak.
- RS (Record separator) Alapértelmezés szerint a sorvége jel, de tetszés szerint megváltoztatható.
- OFS (Output Field Separator) a kiírt mezőket (szavakat) elválasztó karakter. Alapértelmezés szerint a szóköz.
- ORS: (Output Record Separator) a kiírt rekordok (sorok) közötti határolójel. Alapértelmezés szerint az újsor jel.
- OFMT (Output Format) A számok kiírási formátumát tartalmazza. Alapértelmezés szerint OFMT = "%.6g".
Rekordok és mezők
[szerkesztés]A feldolgozott szövegfájl egy sorát rekordnak nevezik. Egy rekord az RS belső változó által meghatározott karakterig tart. RS = "." esetén a rekord hossza éppen egy mondat, függetlenül az újsor jeltől. Vannak előre megadott belső változók, amelyek minden rekord (sor) feldolgozásakor automatikusan értéket kapnak. Például:
- $0 az éppen feldolgozás alatt álló rekordot tartalmazza, vagyis a alapértelmezés szerint a feldolgozás alatt álló sort;
- $1, $2, …$n :a sor egyes elemei, más szavakkal a rekord mezői; alapértelmezés szerint egymástól szóközzel vagy tabulátorjellel elválasztott részei (szavak). A mezők automatikusan jönnek létre a rekord beolvasása során. Ez az automatikus felbontás nagyon egyszerűvé és hatékonnyá teszi az adatfeldolgozást. A mezőkre hivatkozni sorszámukkal lehet:
t = $2 *5
# a t változó a második mező ötszörös értékét veszi fel
k = $1 $3
# a k változóban az első és a harmadik mező összege tárolódik
A mezők indexe csak pozitív egész lehet, negatív mezőhivatkozások (például $-2) fatális hibát okoznak. Az aktuális rekordban lévő mezők számát az NF belső változó tartalmazza. Értéke rekordról rekordra változhat.
Tömbök
[szerkesztés]A tömböket az awk-ban szögletes zárójelekkel []jelölik és minden tömb asszociatív (azaz sztringekkel indexelt). A tömb egyes részeit elválasztó karakter a SUBSEP belső változóban tárolódik. Lehetséges többdimenziós tömbök használata is.
Minták
[szerkesztés]Az awk minták a következők lehetnek:
- /reguláris kifejezés/
- relációs kifejezés
- minta && minta
- minta || minta
- minta ? minta : minta
- (minta)
- ! minta
- minta1, minta2
A legtöbb leírás speciális mintaként tárgyalja a BEGIN
és az END
részeket. Sajnos ezek végrehajtása kötött és nem keverhetők más mintákkal, továbbá nem érvényes rájuk az awk mintákra jellemző inputfüggés sem: a BEGIN
törzse azelőtt hajtódik végre, mielőtt a bemeneti adatok feldolgozása elkezdődne, az END
törzse pedig azután, ha minden bemeneti adat feldolgozása befejeződött. Ezért néhány leírás nem is tekinti őket mintáknak, hanem előkészítő és befejező részként tárgyalja. A BEGIN
és az END
részek törzse nem hiányozhat.
Tevékenységek
[szerkesztés]A tevékenységek utasításai kapcsos zárójelek között szerepelnek.
Operátorok
[szerkesztés]Az awk operátorai között is érvényes a műveleti sorrend (precedencia), amely szerint összetett kifejezésekben először a magasabb precedenciájú műveletek értékelődnek ki. Az AWK operátorai csökkenő precedencia szerint:
Operátor | Jelentése |
---|---|
() | Csoportosítás. |
$ | Mezőhivatkozás. |
-- | Inkrementálás és dekrementálás, lehet prefix és postfix. |
^ | Hatványozás (** szintén, **= pedig értékadó operátorként). |
- ! | Egyoperandusú plusz/mínusz és logikai tagadás. |
* / % | Szorzás, osztás és maradékképzés. |
- | Összeadás és kivonás. |
szóköz | Sztringek összekapcsolása (konkatenáció). |
< > <= >= != == | Relációs operátorok. |
~ !~ | Reguláris kifejezés illeszkedése és nem-illeszkedése. |
in | Tömbhöz tartozás vizsgálata. |
&& | Logikai ÉS. |
|| | Logikai VAGY. |
?: | Feltételes kifejezés. |
= = -= *= /= %= ^= | Értékadás. |
Vezérlő utasítások
[szerkesztés]Legegyszerűbb esetben a vezérlő utasítás(oka)t kapcsos zárójelben lehet elhelyezni. Egy sorban több utasítás is elhelyezhető, ha használják az utasításokat lezáró pontosvesszőt. Példák:
{ print $1 }
{ print $1, $3; print i}
Vezérlő utasításokkal feltételek vizsgálata is elvégezhető vagy ciklusok, ugrások hajthatók végre vagy a tömb(ök) elemei vizsgálhatók, törölhetőek:
- if (feltétel) utasítás [ else utasítás ]
- while (feltétel) utasítás
- do utasítás while (feltétel)
- for (kif1; kif2; kif3) utasítás
- for (var in array) utasítás
- break
- continue
- delete array[index]
- delete array
- exit [ kifejezés ]
Be- és kimeneti utasítások
[szerkesztés]Az awk mindössze néhány be- és kimeneti utasítással rendelkezik, mint például a getline, print, printf, next.
Belső függvények
[szerkesztés]A belső függvények numerikus- sztring- és időfüggvények.
Saját függvények
[szerkesztés]Saját függvény definiálása a function kulcsszó segítségével történhet. Néhány awk-változat elfogadja a rövidebb, négybetűs func alakot is. Például a valami nevű függvény definíciója a következők szerint épül fel:
function valami(paraméterek__és_lokális_változók)
{
függvénytörzs
}
Paraméterek és lokális változók
Ha a saját függvény egy vagy több paramétert vesz át, akkor azokat a függvény neve utáni zárójelben kell megadni, vesszővel elválasztva, hasonlóan a c-nyelvhez. A következő példa három paramétert vár (a, b, és c) továbbá egy lokális változója is van (az i):
function add(a,b,c, i)
{
i= 2;
függvénytörzs
# a függvényből való kilépéskor törlődik az i változó értéke (lokális)
}
Megállapodás szerint a lokális változót egy tabulátor választja el a függvény paramétereitől (megkönnyíti az olvasást). A lokális változók csak a függvény lezáró kapcsos zárójeléig „élnek” és automatikusan megszűnnek. Amennyiben egy változó neve a függvény paraméterei után nincs felsorolva, automatikusan globális változóvá válik:
function add(a,b,c)
{
i = 2;
függvénytörzs
# a függvényből való kilépéskor megőrződik az i változó értéke (globális)
}
Függvénytörzs
A függvény törzsében minden awk-művelet megengedett, beleértve a szabályos kifejezést, értékadást, függvényhívást, mintakeresést és feldolgozást, stb.
A függvénytörzsben a rekurzió megengedett. Visszatérési érték a return
utasítás után adható meg. Amennyiben a return
után nem áll paraméter, úgy a visszatérési érték határozatlan, mint a c-nyelv void-típusú függvényeiben.
A return
számára lokális változó értéke is átadható, mert a lokális változó értékének törlése előtt az érték visszaadására szolgáló memóriaterületre. Előrehivatkozás megengedett, mivel az interpreter először beolvassa az egész programot, és – hibamentes program esetén – csak a teljes program beolvasása után kezdi el végrehajtani. Egy saját függvény definíciója tehát bárhol előfordulhat az awk program szabályai szerint. Így nem fordulhat elő, hogy egy awk-függvény a hívás során még nem ismert: például ha a programban a hívás helye után van definiálva.
Egy egyszerű függvénydefiníció lehet például a következő:
function add_three (number, temp) {
temp = number 3
return temp # temp értékének átmásolása a return területére
} # temp nevű lokális változó törlése
Egy definiált saját függvény a nevének megadásával hívható meg. Saját függvény megadható paraméterként is: A következő példában a print utasítás paramétereként kapja az add_three
függvényt, amely pedig egy numerikus értéket kap paraméterként (esetünkben a 36-ot). Eredményeképpen 39
íródik a kimenetre:
print add_three(36)
Konstansok
[szerkesztés]Az awk kizárólag sztring konstansokat használ, amelyek vezérlésre szolgálnak. A sztring konstansokat idézőjelben kell megadni, például az újsor jele "\n"
Awk parancsok
[szerkesztés]Az awk nyelv szintaxisa hasonlít a C nyelvéhez, ami nem csoda, hiszen az awk nyelv egyik szerzője, Brian W. Kernighan a C nyelv megalkotója. Elemi parancsok a változóknak való értékadás, a változók összehasonlítása, az elágazás (if…else) és a ciklus (for, while). Emellett belső függvényeket, illetve saját implementálású függvényeket is meg lehet hívni. Az adatokat a "print" paranccsal lehet kinyomtatni, azaz a kimenetre írni. Például egy sor második mezője a
print $2
paranccsal íratható ki a szabványos kimenetre.
Példák
[szerkesztés]Helló, világ!
[szerkesztés]A „Helló, világ!” program awk-ban a következőképpen implementálható:
BEGIN { print "Helló, világ!" }
Adott karakterszámnál hosszabb sorok kiíratása
[szerkesztés]A következő programmal a 80 karakternél hosszabb sorokat írja ki. Vegyük észre, hogy az alapértelmezett akció a sor kiírása:
length > 80
Minden n. sor kiírása
[szerkesztés]Adatsorok egyenletes ritkítására is felhasználható az awk. Az alábbi programot végrehajtva az awk minden 4. sort ír a kimenetre:[6]
awk '{if (count %4==0) print $0;}' adatsorom.csv
vagy egyszerűbben:
awk '!(count %4)' adatsorom.csv
Sorok, szavak és karakterek megszámlálása
[szerkesztés]Az alábbi awk program megszámolja, majd kiírja a bemeneti fájlban lévő sorok, szavak és karakterek számát úgy, mint a wc nevű program:
# cnt.awk -- szamlalo
{
w = NF
c = length 1
}
END { print NR, w, c }
Néhány sortól terjedelmesebb awk programokat szokás szövegfájlba (szkript) menteni. Futtatásuk a következő módon is lehetséges:
awk -f cnt.awk < valami.txt
Hatására az interpreter beolvassa az -f
kapcsoló után álló szkriptet (cnt.awk), majd feldolgozza a valami.txt
szövegfájlt a szkript szabályai szerint. Az eredményeket (szavak számát) a képernyőre írja (stdout).
Szavak előfordulási gyakoriságának kiszámítása
[szerkesztés]Szavak gyakoriságáról készít statisztikát asszociatív tömb felhasználásával a következő példa:
#stat.awk
BEGIN { RS="[^a-zA-Z] "}
{ words[tolower($0)] }
END { for (i in words)
print i, words[i]
}
A következő példa feltételes utasítást használ mintakeresésre:
# cal.awk -- kalóriaszámláló
# szövegfájl (táblázat) utolsó oszlopának összegzése és az összeg kiírása
#
# ha nincs érvényes adatpár, akkor az üres bemeneti sorokkal együtt kihagyja
{if (NF > 1){
# minden rekord utolsó mezőjében lévő számértéket az i-be gyűjti, hozzáadogatva
# és kiírja az aktuális sort is
i = $NF; print $0
} # feltétel vége
} # törzs vége
# ha nincs több sor, kiírja az összeg értékét két tabulátor után
END{print "\t\t" i}
Egy awk programban tetszőleges számú megjegyzést lehet elhelyezni. A megjegyzés sorok a rács (hashmark) "#" karakterrel kezdődnek és az aktuális programsor végéig tartanak. A megjegyzések és a strukturált írásmód segítik a programok értelmezését más olvasók számára. Előző példa írható tömörebben is:
# cal.awk
{if (NF > 1){i = $NF; print $0}}
END{print "\t\t" i}
Speciális jelek keresése
[szerkesztés]Néhány karakter az awk-nyelv részére már foglalva van, tehát nem lehet rájuk közvetlenül keresni. Így például a megjegyzés jel # közvetlenül nem tehető mintába, hiszen előfordulása arra utasítja az értelmezőt, hogy a programsor további részét hagyja figyelmen kívül! Hasonlóan nem lehet közvetlenül mintaként megadni a műveleti jeleket, operátorokat sem. A probléma feloldására a speciális karaktereket úgynevezett védő-karakterrel (egy darab per-jellel) kell ellátni, ami arra utasítja az interpretert, hogy a következő karaktert ne a vezérlés részeként, hanem szó szerint értelmezzen. Például a megjegyzést tartalmazó minta a következők szerint kereshető:
# megjegyzés karakter a mintában
/\#/
A keresés megfordítható a negáló (!) operátor segítségével:
# ha: nem megjegyzéssel kezdődő sor, nem üres sor és van érvényes adatpár is
! /^\#/ {if (NF > 1){
Fentieken kívül még számos bonyolultabb program is készíthető awk nyelven, például LISP-interpreter,[7] PRAG a groff részére,[8] stb.
Jegyzetek
[szerkesztés]- ↑ Archivált másolat. [2014. augusztus 26-i dátummal az eredetiből archiválva]. (Hozzáférés: 2014. augusztus 21.)
- ↑ http://awk.info/?jawk Jawk: Awk in Java
- ↑ http://www.tasoft.com/tawk.html TAWK Compiler
- ↑ Egyes operációs rendszereken a megfelelő futtatási jogosultsággal is rendelkezni kell.
- ↑ http://hup.hu/old/gawk/tobb/gawk_14.html#SEC129 Archiválva 2012. augusztus 28-i dátummal a Wayback Machine-ben Felhasználó által definiált függvények
- ↑ UNIX : Cat every nth (third, fourth, fifth ...) line of a text file using AWK. [2007. augusztus 26-i dátummal az eredetiből archiválva]. (Hozzáférés: 2009. június 9.)
- ↑ http://awk.info/?dsl/awklisp AWKLISP
- ↑ Archivált másolat. [2014. augusztus 26-i dátummal az eredetiből archiválva]. (Hozzáférés: 2014. augusztus 21.)
Kapcsolódó szócikkek
[szerkesztés]További információk
[szerkesztés]- A GNU Awk felhasználói kézikönyve
- Alfred V. Aho, Brian W. Kernighan, and Peter J. Weinberger: Az AWK Programozási nyelv. Addison-Wesley, 1988, ISBN 0-201-07981-X
- [1] – az eredeti Awk
- comp.lang.awk – Usenet hírcsoport
- [2] – GAWK (GNU Awk) Weboldal
- [3] – AWK-bevezető németül
- The awk programming language