Go to the 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.