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.