awk

A Wikipédiából, a szabad enciklopédiából
(Awk programozási nyelv szócikkből átirányítva)

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]