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.
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.
Az alábbi táblázat felsorolja az awk
-ban használható minták típusát.
/reguláris kifejezés/
kifejezés
pat1, pat2
BEGIN
END
awk
programokban.
(See section A BEGIN
és az END
speciális minták.)
üres
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" }
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.
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.
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.
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.
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 (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.
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:
awk
program futásának folyamatát
határozzák meg. Az awk
nyelv a C programozási nyelvben használható
utasításokat biztosítja (if
, for
, while
és do
)
és néhány speciálisat
(see section Vezérlésátadó kifejezések a tevékenységekben).
if
, a while
, a do
vagy a for
kifejezések testében.
getline
parancs
(see section Explicit beolvasás getline
-al), a next
parancs
(see section A next
kifejezés),
és a nextfile
parancs
(see section A nextfile
kifejezés).
print
és printf
.
See section Kimenet megjelenítése.
delete
kifejezés.
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.