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 nevű 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

  1. Archivált másolat. [2014. augusztus 26-i dátummal az eredetiből archiválva]. (Hozzáférés: 2014. augusztus 21.)
  2. http://awk.info/?jawk Jawk: Awk in Java
  3. http://www.tasoft.com/tawk.html TAWK Compiler
  4. Egyes operációs rendszereken a megfelelő futtatási jogosultsággal is rendelkezni kell.
  5. 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
  6. 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.)
  7. http://awk.info/?dsl/awklisp AWKLISP
  8. 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