first, previous, next, last section, table of contents.


Minták és tevékenységek

Mint azt már láttuk, minden awk szabály tartalmaz egy mintát és egy ahhoz kapcsolódó tevékenységet. Ez a fejezet azt mutatja be, hogy hogyan kell mintákat és tevékenységeket összeállítani.

Minta elemek

Az awk-ban a minták határozzák meg a szabályok végrehajtási sorrendjét: a szabály végrehajtódik, ha a minta illeszkedik az adott bemeneti rekordra. Ez a bekezdés elmagyarázza, hogy hogyan írjunk mintákat.

Minta típusok

Az alábbi táblázat felsorolja az awk-ban használható minták típusát.

/reguláris kifejezés/
Egy reguláris kifejezés, mint minta, illeszkedik minden olyan bemeneti rekordra ami illeszkedik a reguláris kifejezés által megadott szövegre. (See section Reguláris kifejezések.)
kifejezés
Egy kifejezés illeszkedik ha az értéke nem zérus (ha egy szám) vagy nem üres szöveg. (See section Kifejezések mint minták.)
pat1, pat2
Egy minta pár, vesszővel elválasztva egy rekord tartományt határoz meg. A tartomány tartalmazza a kezdeti rekordot ami illeszkedik a pat1-re és a végső rekordot ami illeszkedik a pat2-re. (See section Rekord tartományok definiálása mintákkal.)
BEGIN
END
Speciális minták kezdeti vagy végső tevékenységek definiálásához awk programokban. (See section A BEGIN és az END speciális minták.)
üres
Az üres minta illeszkedik minden bemeneti rekordra. (See section Az üres minta.)

Reguláris kifejezések mint minták.

Már eddig is használtunk reguláris kifejezéseket mintaként a példákban. Ez a típusú minta egy egyszerű regexp konstans a szabály minta pozíciójában, és jelentése megfelel a `$0 ~ /pattern/' kifejezésnek. A minta illeszkedik, amikor a bemeneti rekordra illeszkedik a regexp. Például:

/foo|bar|baz/  { buzzwords++ }
END            { print buzzwords, "buzzwords seen" }

Kifejezések mint minták

Bármilyen awk kifejezés érvényes awk minta és a minta illeszkedik ha a kifejezés értéke nem zérus (ha egy szám) vagy nem üres szöveg.

A kifejezések minden alkalommal kiértékelődnek, amikor a szabályt teszteli egy új bemeneti rekorddal. Ha a kifejezés mezőket használ mint $1, az érték közvetlenül függ az új bemeneti rekord szövegétől; máskülönben attól függ, hogy mi történt eddig az awk program végrehajtása során.

Egy nagyon gyakori kifejezés mint minta az összehasonlító kifejezés, ami összehasonlító operátort használ, see section Változó típusok és az összehasonlító kifejezések.

A regexp illeszkedés és nem illeszkedés is gyakori kifejezések. A `~' és a `!~' operátorok bal oldali operandusa egy szöveg. A jobb oldali operandus vagy egy konstans reguláris kifejezés a `/' karakterek közé zárva (/regexp/) vagy bármilyen kifejezés aminek a szöveg értéke mint dinamikus reguláris kifejezés használható (see section Dinamikus reguláris kifejezések használata).

A következő példa minden olyan bemeneti rekord második rekordját kinyomtatja aminek az első mezője pontosan a `foo' szöveg.

$ awk '$1 == "foo" { print $2 }' BBS-list

(Nincs kimenet, mivel nincs "foo" nevű BBS állomás.) Ezzel ellentétben nézzük az alábbi reguláris kifejezést, ami bármilyen rekordra illeszkedik aminek az első mezője `foo' szöveget tartalmaz.

$ awk '$1 ~ /foo/ { print $2 }' BBS-list
-| 555-1234
-| 555-6699
-| 555-6480
-| 555-2127

A logikai kifejezések szintén gyakran használt minták, és hogy egy minta illeszkedik egy bemeneti rekordra attól függ, hogy az alkifejezés illeszkedik-e.

Például az alábbi parancs kinyomtat minden olyan rekordot a `BBS-list' file-ból, ami tartalmazza a `2400' és a `foo' szövegeket.

$ awk '/2400/ && /foo/' BBS-list
-| fooey        555-1234     2400/1200/300     B

Az alábbi parancs kinyomtat minden olyan rekordot a `BBS-list' file-ból, ami vagy a `2400' vagy a `foo' vagy mindkettő szöveget tartalmazza.

$ awk '/2400/ || /foo/' BBS-list
-| alpo-net     555-3412     2400/1200/300     A
-| bites        555-1675     2400/1200/300     A
-| fooey        555-1234     2400/1200/300     B
-| foot         555-6699     1200/300          B
-| macfoo       555-6480     1200/300          A
-| sdace        555-3430     2400/1200/300     A
-| sabafoo      555-2127     1200/300          C

Az alábbi parancs kinyomtat minden olyan rekordot a `BBS-list' file-ból, ami nem tartalmazza a `foo' szöveget.

$ awk '! /foo/' BBS-list
-| aardvark     555-5553     1200/300          B
-| alpo-net     555-3412     2400/1200/300     A
-| barfly       555-7685     1200/300          A
-| bites        555-1675     2400/1200/300     A
-| camelot      555-0542     300               C
-| core         555-2912     1200/300          C
-| sdace        555-3430     2400/1200/300     A

Egy mintában előforduló logikai operátor alkifejezései lehetnek konstans reguláris kifejezések, összehasonlító vagy bármilyen awk kifejezések. A tartomány minták nem kifejezések, így nem szerepelhetnek logikai kifejezésekben. A BEGIN és az END speciális minták soha nem illeszkednek bemeneti rekordra, nem kifejezések és nem szerepelhetnek logikai mintában.

Egy regexp konstans mint minta szintén egy speciális kifejezés minta. A /foo/ mint kifejezésnek egy az értéke ha a `foo' szöveg előfordul a jelenlegi bemeneti rekordban; így, mint minta, a /foo/ illeszkedik minden olyan rekordra ami tartalmazza a `foo' szöveget.

Rekord tartományok definiálása mintákkal

A tartomány minta két vesszővel elválasztott mintából áll az alábbi formában `kezdminta, végminta', és a bemeneti rekordok egymás utáni tartományára illeszkedik. Az első minta, kezdminta, adja meg a tartomány kezdetét és a második, végminta, határozza meg a végét. Például:

awk '$1 == "on", $1 == "off"'

kinyomtat minden rekordot az `on'/`off' pár között, a kezdő és a záró sorokat is beleértve.

Tartomány minta esetén először a kezdminta mintát keresi meg minden bemeneti rekord között. Amikor sikerül megtalálni a kezdminta mintát, a tartomány minta bekapcsol. A tartomány minta illeszkedik az adott rekordra is, és addig amíg bekapcsolva marad, automatikusan illeszkedik minden beolvasott bemeneti rekordra. Ezen kívül minden rekordot megpróbál illeszteni az végminta mintával is; amikor ez sikerül a tartomány minta kikapcsol a következő rekordra. Ekkor ismét a kezdminta mintát keresi a rekordok között.

Az a rekord, ami be- illetve kikapcsolja a tartomány mintát szintén illeszkedik a tartomány mintára. Ha ezeken a rekordokon nem akarunk dolgozni, akkor egy if kifejezést kell használni a szabályok tevékenység részében, hogy kigyüjtsük azokat a rekordokat amik érdekelnek.

Lehetséges, hogy egy minta be- és ki is kapcsolódik ugyanazon rekord által, ha a rekord mindkét feltételt teljesíti. Ekkor a tevékenység csak az adott rekordra hajtódik végre.

Például, tegyük fel hogy két azonos jel (mondjuk a `%' szimbólum) közötti szöveged van, amit szeretnél elhagyni egy másik szövegből. Összekombinálhatod a tartomány mintát a next kifejezéssel (eddig nem tárgyaltuk, see section A next kifejezés), aminek hatására az awk átugorja a jelenlegi rekord minden további feldolgozását, és újrakezdi a következő rekorddal. Egy ilyen program így nézne ki:

/^%$/,/^%$/    { next }
               { print }

Ez a program nem működik, mivel a tartomány mintát be- és ki is kapcsolja az első sor ami a `%' szimbólumot tartalmazza. Ahhoz, hogy valóban működjön a program, valahogy így kellene kinéznie:

/^%$/     { skip = ! skip; next }
skip == 1 { next } # skip lines with `skip' set

Érdemes megjegyezni, hogy a tartomány mintában a vesszőnek (`,') van a legalacsonyabb precedenciája és ezért utolsóként értékelődik ki az operátorok közül. Így, például, a következő program megpróbál egy tartomány mintát és egy egyszerűbb tesztet összekombinálni.

echo Yes | awk '/1/,/2/ || /Yes/'

Ennek a programnak a szerzője úgy értette, hogy `(/1/,/2/) || /Yes/', de az awk ezt úgy értelmezi, hogy `/1/, (/2/ || /Yes/)'. Ezt nem lehet megváltoztatni vagy valami trükkel elkerülni; tartomány minták nem kombinálhatók más mintákkal.

A BEGIN és az END speciális minták

A BEGIN és az END speciális minták. Ezek a minták nem illeszkednek semmilyen bemeneti rekordra, ezzel szemben kezdő és lezáró tevékenységet biztosítanak egy awk program számára.

Kezdő és lezáró tevékenységek

A BEGIN szabály csak egyszer hajtódik végre, mielőtt beolvasná az első bemeneti rekordot. Az END szabály is csak egyszer hajtódik végre, miután beolvasott minden bemenetet. Például:

$ awk '
> BEGIN { print "Analysis of \"foo\"" }
> /foo/ { ++n }
> END   { print "\"foo\" appears " n " times." }' BBS-list
-| Analysis of "foo"
-| "foo" appears 4 times.

Ez a program megszámolja azokat a rekordokat a `BBS-list' file-ban, amelyek tartalmazzák a `foo' szöveget. A BEGIN szabály kinyomtatja a report fejlécét, ugyanakkor nincs arra szükség, hogy a BEGIN szabályban az n számlálót zérus értékkel inicializáljuk, mivel az awk megteszi ezt automatikusan (see section Változók).

A második szabály megnöveli az n változót minden alkalommal, amikor a rekord tartalmazza a `foo' mintát. Az END szabály kinyomtatja az n változó értékét a futás végén.

A BEGIN és az END speciális szabályokat nem lehet sem tartomány mintában, sem logikai operátorral használni (valójában semmilyen operátorral nem lehet kombinálni).

Egy awk program tartalmazhat több BEGIN és/vagy END szabályt is. A megjelenési sorrendben hajtódnak végre, a BEGIN szabályok kezdetben és az END szabályok a program legvégén. A BEGIN és az END szabályok összekeverhetők más szabályokkal. Ezt a lehetőséget 1987-ben adták az awk-hoz és bekerült a POSIX szabványba. Az awk eredeti (1987-es) verziója megkívánta, hogy a BEGIN szabály a program elején álljon és az END szabály a legvégén, ezenkívül csak egy BEGIN és csak egy END minta volt használható. Ez ma már nincs így, de jó ötlet ha a program olvashatóságát vagy szervezését tekintjük fő szempontnak.

A többszörös BEGIN és END szabályok hasznosak könyvtár függvények írásánál, mivel minden könyvtári file-nak lehet saját BEGIN és/vagy END szabálya, ami elvégzi a szükséges inicializálást és/vagy takarítást. Fontos figyelembe venni, hogy amilyen sorrendben a könyvtári függvények megjelennek a parancssorban az meghatározza a BEGIN és az END szabályok végrehajtási sorrendjét is. Ezért fontos, hogy óvatosan írjunk ilyen szabályokat a könyvtár file-okba, mivel így a végrehajtási sorrend nem számít. See section A Library of awk Functions, ami bemutat néhány hasznos könyvtári függvényt.

Ha egy awk programban csak egy BEGIN szabály van és semmilyen más szabály nincs akkor a program kilép a BEGIN szabály végrehajtása után. (Az awk eredeti verizója folyamatosan olvasott, és minden bemenetet eldobott addig, amíg egy file vége jelet nem kapott.) Ugyanakkor ha van egy END szabály a programban, akkor a bemenetet mindenképpen olvasni fogja, még akkor is, ha nincs semmilyen más szabály a programban. Ez szükséges abban az esetben ha az END szabály használná a FNR és a NR változókat (s.s.).

A BEGIN és az END szabályoknak kell legyen tevékenység része; ezeknél a szabályoknál nincs alaptevékenység.

Bemenet/kimenet a BEGIN és az END szabályokban

Van néhány (néha csak apró), de fontos kérdés az I/O-val kapcsolatban, amikor a BEGIN vagy az END szabályokon belül használjuk.

Az első kérdés, hogy mi lesz a $0 értéke a BEGIN szabályon belül. Mivel a BEGIN szabály a bemenet beolvasása előtt hajtódik végre, ezért nincs semmilyen bemeneti rekord, és nincsennek mezők a BEGIN szabály végrehajtása során. Ha a $0-ra vagy bármilyen mezőre hivatkozunk, akkor egy üres szöveget vagy zérus értéket kapunk, az adott helyzettől függően. Az egyik lehetőség, hogy a $0-nak valódi értéket adjunk a getline parancs használatával (see section Explicit beolvasás getline-al). A másik lehetőség, hogy értéket rendelünk hozzá.

A második kérdés hasonló az elsőhöz, de a másik irányból közelíti meg a problémát. Az END szabályon belül mi a $0 és az NF értéke? Hagyományosan, főleg az implementációknak köszönhetően, a $0 és a NF értéke nem definiált az END szabályon belül. A POSIX szabvány azt definiálja, hogy az NF elérhető az END szabályon belül, és az utolsó bemeneti rekordban előforduló mezők számát tartalmazza. Valószínűleg csak tévedésből a szabvány nem rendelkezik a $0 értékének megőrzéséről, de ez lenne logikus. Valójában a gawk így is tesz és megőrzi a $0 értékét az END szabályon belül, de jegyezd meg, hogy a UNIX awk és valószínűleg más implementációk nem így viselkednek.

A harmadik kérdés következik az első kettőből. Mit jelent a `print' parancs a BEGIN és az END szabályon belül? A jelentése persze ugyanaz, `print $0'. Ha a $0 egy üres szöveg, akkor egy üres sort nyomtat ki. Régen az awk programozók a BEGIN és az END szabályokon belül a `print' parancsot használták a `print ""' helyett, abban bízva, hogy a $0 egy üres szöveg. Bár ez gyakran igaz a BEGIN szabályon belül, legalább is a gawk-ban, de nagyon rossz ötlet az END szabályon belül. Ugyanakkor rossz programozói stílus is, mivel ha üres sort akarunk kinyomtatni, akkor adjuk azt meg a programnak.

Az üres minta

Az üres (vagyis nem létező) minta illeszkedik minden bemeneti rekordra. Például, a program:

awk '{ print $1 }' BBS-list

kinyomtatja minden rekord első mezőjét.

Tevékenységek áttekintése

Egy awk program "script"-szabályok és függvénydefiníciók keveréke. (A függvényeket később tárgyaljuk, see section Felhasználó által definiált függvények.)

Egy szabály egy mintát és egy tevékenységet tartalmaz, bármelyik (de egyszerre mind a kettő nem) hagyható el. A tevékenység mondja meg az awk-nak, hogy mit kell csinálni, ha megtalálta a keresett mintát. Úgy nagyjából, egy awk program így néz ki:

[minta] [{ tevékenység }]
[minta] [{ tevékenység }]
...
function név(argumentumok) { ... }
...

Egy tevékenység egy vagy több awk kifejezésből áll kapcsos zárójelek között (`{' és `}'). Minden kifejezés meghatároz egy dolgot. A kifejezéseket új sor vagy pontosvessző karakterek választják el egymástól.

A kapcsos zárójelekre mindig szükség van a tevékenységek körül még akkor is, ha csak egy kifejezésből áll, vagy nincs is benne kifejezés. Ugyanakkor ha a tevékenységet elhagyjuk, akkor a kapcsos zárójeleket is el lehet hagyni. Az elhagyott tevékenység megegyezik a `{ print $0 }' kifejezéssel.

/foo/  { }  # foo-ra illeszkedik, nem csinál semmit
/foo/       # foo-ra illeszkedik, kinyomtatja a rekordot

Az awk-ban használható kifejezéseket alább soroljuk fel:

A következő fejezet a vezérlésátadó kifejezéseket tárgyalja részletesen.


Go to the first, previous, next, last section, table of contents.