A vezérlésátadó kifejezések, mint az if, a while és így tovább,
az awk program végrehajtásának folyamatát befolyásolják. Az awk
vezérlésátadó kifejezései a C programozási nyelv kifejezésein alapulnak.
Minden vezérlésátadó kifejezés egy speciális kulcsszóval kezdődik, mint az if
és a while, azért hogy megkülönböztethetők legyenek az egyszerű
kifejezésektől.
Sok vezérlésátadó kifejezés magába foglal más kifejezéseket is; például
az if kifejezés olyan kifejezéseket is tartalmaz, amiket vagy végrehajt
vagy nem. Ezek a kifejezések alkotják a vezérlésátadó kifejezés testét.
Ha egynél több kifejezést akarunk összefogni a vezérlésátadó kifejezés testében
akkor ezt egy összetett kifejezéssel, kapcsos zárójelek között lehet
megtenni. A kifejezéseket új sorral vagy a pontos vessző karakterrel lehet
elválasztani egymástól.
if-else kifejezés
Az if-else kifejezés az awk döntéshozó kifejezése és
így néz ki:
if (feltétel) then-test [else else-test]
A feltétel kifejezés befolyásolja, hogy a kifejezés további része
mit csinál. Ha a feltétel igaz, akkor a then-test hajtódik
végre; egyébként a else-test fut le.
A kifejezés else része opcionális. A feltétel hamis ha az értéke
zérus vagy üres szöveg, egyébként igaz.
Íme egy példa:
if (x % 2 == 0)
print "x páros"
else
print "x páratlan"
Ebben a példában, ha a `x % 2 == 0' kifejezés igaz (vagyis az x
értéke osztható kettővel), akkor az első print parancs hajtódik végre,
más esetben a második print fog lefutni.
Ha az else a then-testel egy sorban jelenik meg és a
then-test nem összetett kifejezés (pl. nincs kapcsos zárójelek között),
akkor egy pontos vesszőnek kell elválasztania a then-testet az
else-től. Ennek bemutatására, írjuk át az előző példát:
if (x % 2 == 0) print "x páros"; else
print "x páratlan"
Ha elfelejtjük a `;' -t kitenni, akkor az awk nem képes
értelmezni a kifejezést és szintaktikai hibát fog jelezni.
Valójában nem érdemes így írni a példát, mivel egy emberi olvasó lehet,
hogy nem veszi észre az else kifejezést, ha az nem az első szó
a sorban.
while kifejezésA programozásban a hurok vagy a ciklus azt jelenti, hogy a program egymás után kétszer vagy többször hajtja végre ugyanazt a részt.
A while kifejezés a legegyszerűbb hurokképző kifejezés az awk-ban.
A while addig hajt végre más kifejezéseket, amíg a feltétel igaz. A
kifejezés formája:
while (feltétel) test
A test tartalmazza a végrehajtandó kifejezéseket, és a feltétel az a kifejezés, ami szabályozza, hogy a hurok hányszor fusson le.
A while kifejezés először kiértékeli a feltétel kifejezést.
Ha a feltétel igaz, akkor végrehajtja a test kifejezést.
Miután a test végrehajtódott, a feltételt újra kiértékeli,
és ha még mindig igaz, akkor a test ismét lefut. Ezt az eljárást
addig ismétli, amíg a feltétel hamis nem lesz. Ha a feltétel
kezdetben hamis, akkor a hurok teste soha nem hajtódik végre, és az awk
a hurok utáni kifejezéssel folytatja a program végrehajtását.
Ez a példa minden rekord első három mezőjét nyomtatja ki, egyet egy sorba.
awk '{ i = 1
while (i <= 3) {
print $i
i++
}
}' inventory-shipped
Itt a hurok teste egy összetett kifejezés kapcsos zárójelek között, ami két kifejezésből áll.
A hurok valahogy így működik: először az i értéke egy lesz. Ezután
a while ellenőrzi, hogy az i kisebb-e mint három vagy egyenlő-e
hárommal. Ez igaz, hiszen az i értéke egy, így kinyomtatja az
i-edik mezőt. Ezek után a `i++' kifejezés megnöveli az
i értékét, majd a hurok megismétli ezt a folyamatot. A hurok
véget ér amikor az i értéke négy lesz.
Mint látható, új sor nem szükséges a feltétel és kifejezés teste között, de a kifejezés több sorba szedése jobban olvashatóvá teszi a programot. Kivéve persze ha összetett kifejezést használunk vagy nagyon egyszerű kifejezést. Az új sor a nyitó zárójel után, ami az összetett kifejezést elkezdi szintén nem szükséges, de akkor a programot nehezebb olvasni.
do-while kifejezés
A do hurok a while hurok kifejezés egy változata. A do
hurok kifejezés egyszer végrehajtja a testet, és ezt addig ismétli
amíg a feltétel igaz. A formája az alábbi:
do test while (feltétel)
Még ha a feltétel kezdetben hamis is, a test legalább egyszer
végrehajtódik (és csak egyszer, hacsak a test igazzá nem teszi a
feltételt. Érdemes ezt összehasonlítani az alábbi while
kifejezéssel:
while (feltétel) test
Ez a kifejezés nem hajtja végre a test kifejezést egyszer sem, ha a feltétel hamis kezdetben.
Itt egy példa a do kifejezésre:
awk '{ i = 1
do {
print $0
i++
} while (i <= 10)
}'
Ez a program minden rekordot tízszer nyomtat ki. Ez nem egy valós példa,
mivel egy közönséges while hurok is megtenné. Ugyanakkor egy
tapasztalatot is tükröz, hogy nagyon ritkán van valós indok a
do kifejezés használatára.
for kifejezés
A for kifejezés kényelmessé teszi iterációs ciklusok készítését. A
for kifejezés általános formája:
for (inicializálás; feltétel; növelés) test
Az inicializálás, a feltétel és a növelés tetszőleges
awk kifejezések és a test az ismételten végrehajtandó awk
kifejezés.
A for kifejezés először az inicializálás kifejezést hajtja végre.
Ezután, amíg a feltétel igaz, ismételten végrehajtja a testet
majd az növelés kifejezést. Tipikusan az inicializálás a
változót egyre vagy zérusra állítja, a növelés eggyel növeli azt és a
feltétel ellenőrzi, hogy az iterációk száma elérte-e a kívánt értéket.
Itt egy példa a for kifejezésre:
awk '{ for (i = 1; i <= 3; i++)
print $i
}' inventory-shipped
A program minden bemeneti rekord első három mezőjét kinyomtatja, egy mezőt soronként.
Egynél több változót nem lehet beállítani az inicializálás részben
kivéve a többszörös értékadás, mint `x = y = 0', ami csak akkor
használható ha minden változó kezdeti értéke egyenlő. (Persze a pótlólagos
változóknak külön-külön is értéket adhatunk a for ciklus előtt.)
Ugyanez igaz a növelés részre is; ahhoz, hogy egynél több változót
növeljünk meg, a ciklus végén kell ezt elvégezni külön kifejezésekkel. A C
programozási nyelvben az összetett kifejezések kialakítására használható
vessző operátor az ilyen esetekben hasznos lehet, de az awk-ban
nem támogatott.
Leggyakrabban a növelés egy növelő kifejezés, mint a fenti példában. De ez nem kötelező; ez bármilyen kifejezés lehet. Például, ez a kifejezés kinyomtatja a kettes szám egy és száz közé eső hatványait:
for (i = 1; i <= 100; i *= 2) print i
A for utáni zárójelek közé eső három paraméter közül bármelyik
elhagyható, ha abban a pozícióban nincs mit csinálni. Így a
`for (; x > 0;)' kifejezés egyenértékű a `while (x > 0)'
kifejezéssel. Ha a feltétel nincs megadva, akkor a feltétel mindig
true, vagyis igaz, ami egy végtelen ciklust eredményez (pl.
a ciklus soha nem ér véget).
A legtöbb esetben, egy for ciklus egy while hurok rövidítése,
ahogy ezt alább bemutatjuk:
inicializálás
while (feltétel) {
test
növelés
}
Az egyetlen kivétel, amikor a continue kifejezés
(see section A continue kifejezés)
szerepel a ciklusban. Ebben az esetben ha a for kifejezést
átalakítjuk while kifejezésre, akkor a continue kifejezés
hatását is könnyen megváltoztathatjuk akaratlanul.
A for ciklusnak van egy alternatív formája, ami egy tömb elemein
megy végig:
for (i in tömb)
csinálj valamit az elemmel array[i]
A section Egy tömb elemeinek ellenőrzése,
további információt tartalmaz a for ciklus ezen verziójáról.
Az awk nyelv a while hurokképző kifejezésen kívül a for
kifejezéssel is rendelkezik, mivel egy for ciklus begépelése kevesebb
időt vesz igénybe, és egy természetesebb gondolkodást támogat. Az iterációs
lépések számolása egy természetes feladat a ciklusokban. Egyszerűbb erről
úgy gondolkodni, hogy ez a számolás a ciklus része, mint hogy a cikluson
belül kelljen ezt elvégezni.
A következő fejezetben bonyolultabb for ciklusokat mutatunk be.
break kifejezés
A break kifejezés a legbelsőbb for, while vagy
do hurokból lép ki. A következő példa egy egész szám legkisebb
osztóját keresi meg, és azonosítja a prímszámokat is:
awk '# legkisebb osztó keresése
{ num = $1
for (div = 2; div*div <= num; div++)
if (num % div == 0)
break
if (num % div == 0)
printf "A %d legkisebb osztója a %d\n", num, div
else
printf "%d prím\n", num
}'
Ha a maradék zérus az első if kifejezésben, az awk azonnal
kilép a for ciklusból. Ez azt jelenti, hogy az awk
közvetlenül a ciklus utáni kifejezéssel folytatódik. (Ez teljesen különböző
az exit kifejezéstől, ami az egész awk programból lép ki.
See section Az exit kifejezés.)
Itt van még egy program, ami teljesen azonos az előzővel és bemutatja, hogy
hogyan lehet a for vagy a while kifejezés feltétel
részét lecserélni egy if és egy break kifejezéssel:
awk '# find smallest divisor of num
{ num = $1
for (div = 2; ; div++) {
if (num % div == 0) {
printf "Smallest divisor of %d is %d\n", num, div
break
}
if (div*div > num) {
printf "%d is prime\n", num
break
}
}
}'
Mint azt már korábban elmondtuk, a break kifejezésnek nincs semmi
jelentése egy ciklus testén kívül. Ugyanakkor, bár ez soha nem volt
dokumentálva, az awk régebbi implementációi a break kifejezést
egy cikluson kívül úgy kezelték mint egy next kifejezés
(see section A next kifejezés).
Az awk jelenlegi implementációi többé nem támogatják ezt a viselkedést.
A gawk támogatja a break ilyen viselkedését ha a parancssorban
a `--traditional' opció is meg van adva
(see section Command Line Options).
Más esetekben hibát eredményez, mivel a POSIX szabvány a break
kifejezést úgy definiálja, hogy csak cikluson belül használható (s.s.).
continue kifejezés
A continue kifejezés, mint a break kifejezés csak a
for, a while és a do cikluson belül használható.
A continue kifejezés végrehajtása a ciklus további részét
átugorja, aminek
hatására az újabb ciklus elkezdődik. Ezzel ellentétben a break
kilép a ciklusból.
Egy for ciklusbeli continue kifejezés arra utasítja az
awk-ot, hogy ugorja át a ciklus további részét és a for
kifejezés növelő kifejezés részével folytassa a futtatást. Az alábbi
program ezt a tényt illusztrálja:
awk 'BEGIN {
for (x = 0; x <= 20; x++) {
if (x == 5)
continue
printf "%d ", x
}
print ""
}'
Ez a program kinyomtatja a számokat zérustól 20-ig, kivéve az ötös számot,
amikor a printf kifejezést átugorja. Mivel a növelő `x++'
kifejezést nem ugorja át, az x változónak nem öt lesz az értéke
ezek után. A fenti for ciklust érdemes összehasonlítani az alábbi
while ciklussal:
awk 'BEGIN {
x = 0
while (x <= 20) {
if (x == 5)
continue
printf "%d ", x
x++
}
print ""
}'
Ez a program végtelen ciklusba kerül miután az x változó öt értéket
kap.
Mint azt már korábban elmagyaráztuk, a continue kifejezésnek nincs
értelme egy cikluson kívül. Ugyanakkor, bár eddig nem volt dokumentálva,
az awk régi implementációjában a continue kifejezés
cikluson kívüli használata a next kifejezésnek felelt meg
(see section A next kifejezés).
A Unix awk jelenlegi implementációi nem támogatják ezt a viselkedést.
A gawk lehetővé teszi ezt viselkedést ha a `--traditional' opció
szerepel a parancssorban
(see section Command Line Options).
Minden más esetben ez hibát jelent, mivel a POSIX szabvány a continue
ilyen viselkedését nem definiálja (s.s.).
next kifejezés
A next kifejezés arra utasítja az awk-ot, hogy azonnal
fejezze be a jelenlegi rekord feldolgozását és folytassa a következő rekorddal.
A jelenlegi szabály további tevékenység részét sem hajtja végre.
Érdemes ezt összehasonlítani a getline függvény hatásával
(see section Explicit beolvasás getline-al). A getline
kifejezés hatására is az awk azonnal beolvassa a következő rekordot, de nem
változtatja meg a program futási folyamatát semmilyen módon. Így az
aktuális tevékenység az új rekorddal folytatja a feldolgozást.
A legmagasabb szinten egy awk program végrehajtása egy olyan ciklus,
ami beolvassa a bemeneti rekordokat és minden szabállyal szemben teszteli is
azokat. Ha erre a ciklusra úgy gondolsz, mint egy for kifejezésre,
aminek a testét a szabályok alkotják, akkor a next kifejezés megfelel a
continue kifejezésnek: átugorja a ciklus testének végét és a
növelés kifejezést hajtja végre (ami ebben az esetben beolvassa a következő
rekordot).
Például, ha az awk programod csak négy mezőből álló rekordokon
dolgozik és nem akarod, hogy rossz bemenet esetén felmondja a szolgálatot
akkor egy ilyen szabályt használhatsz a program elején:
NF != 4 {
err = sprintf("%s:%d: skipped: NF != 4\n", FILENAME, FNR)
print err > "/dev/stderr"
next
}
így a következő szabályok nem kapják meg a rossz rekordot. A hibaüzenet
át van irányítva a szabványos hibakimenetre, mint ahogy minden
hiba esetén lennie kell.
See section Speciális file nevek gawk-ban.
A POSIX szabvány szerint, a next kifejezés viselkedése nem definiált
a BEGIN és az END szabályokban. A gawk szintaktikai
hibát fog jelezni. Bár a POSIX szabvány megengedi, de néhány awk
implementáció nem engedi meg a next kifejezés használatát egy
függvényben
(see section Felhasználó által definiált függvények).
Mint minden más next kifejezés, a függvény belsejében elhelyezett
next kifejezés is beolvassa a következő rekordot és elkezdi
feldolgozni a program első szabályával.
Ha a next kifejezés használatával eléri a bemenet végét, akkor
az END szabályon belüli kódot hajtja végre.
See section A BEGIN és az END speciális minták.
Figyelem: Néhány awk implementáció futási időben hibát
generál, ha egy a felhasználó által definiált függvényen belül a next
kifejezést használjuk
(see section Felhasználó által definiált függvények).
A gawk-nak nincs ilyen problémája.
nextfile kifejezés
A gawk a next kifejezéshez hasonlóan egy nextfile
kifejezést is biztosít. Ugyanakkor az aktuális rekord eldobása helyett
a nextfile kifejezés arra utasítja a gawk-ot, hogy
fejezze be az adott adat file feldolgozását.
A nextfile kifejezés hatására a parancssorbeli következő
file nevével tölti fel a FILENAME változót, az FNR változót
egyre állítja, az ARGIND változót megnöveli és elkezdi a
feldolgozást a program első szabályától.
See section Beépített változók.
Ha a nextfile kifejezés hatására eléri a bemenet végét, akkor az
END szabály kódja hajtódik végre.
See section A BEGIN és az END speciális minták.
A nextfile kifejezés egy gawk kiegészítés; (jelenleg)
nem használható más awk implementációkban.
See section Implementing nextfile as a Function,
ahol bemutatjuk, hogy a felhasználó által definiált függvénnyel
is szimulálható a nextfile kifejezés.
A nextfile kifejezés hasznos lehet ha több adatfile-t kell feldolgozni,
és nem akarod minden file minden rekordját feldolgozni. Normális esetben
ahhoz, hogy a következő file feldogozását elkezdhesd, a szükségtelen
rekordokat is át kellene nézni. A nextfile kifejezés ezt kerüli el
hatékonyan.
Figyelem: A gawk 3.0-ás verziója előtt két azonos szó
állt rendelkezésre ugyanarra a kifejezésre, a `next file' és a
nextfile. Ez megváltozott a 3.0-ás verziótól kezdve, mivel a
file kulcsszó kezelése így nem volt következetes. Ha a next
után szerepelt akkor kulcsszó volt, egyébként meg egy egyszerű azonosító.
A régi használat még mindig elfogadott. Ugyanakkor a gawk figyelmeztető
üzenetet generál és a gawk jővőbeli verzióiban a next file
kifejezés nem támogatott.
exit kifejezés
Az exit kifejezés hatására az awk azonnal befejezi az aktuális
szabály végrehajtását, és abbahagyja a bemenet feldolgozását is; minden további
bemenetet figyelmen kívül hagy. A formája az alábbi:
exit [visszatérési érték]
Ha egy exit kifejezést hajt végre az awk a BEGIN
szabályban akkor azonnal befejez minden működést. Semmilyen bemenetet
nem olvas be. Ugyanakkor ha egy END szabály is van a programban,
akkor azt is végrehajtja
(see section A BEGIN és az END speciális minták).
Ha egy exit kifejezés hajtódik végre az END szabályban,
akkor a program azonnal leáll.
Egy exit kifejezés ami nem része sem egy BEGIN sem egy
END szabálynak azonnal befejezi a további szabályok
végrehajtását az adott rekordra, átugorja a további bemeneti rekordokat
és végrehajtja az END szabályt, ha van ilyen.
Ha azt akarod, hogy az END szabály ne fusson le ebben az esetben,
akkor egy változót be kell állítani egy nem zérus értékre az exit
kifejezés előtt, és ezt a változót ellenőrizni kell az END szabályon
belül.
See section Assertions,
ami egy példát tartalmaz erre.
Ha egy argumentumot is megadunk az exit kifejezésnek, akkor ez
az érték lesz az awk kimeneti státusz kódja, visszatérési
értéke. Ha nincs argumentum
megadva, akkor az exit státusza zérus lesz (siker). Abban az
esetben amikor először az exit kifejezésnek egy argumentumot adunk
meg, majd a második esetben nem argumentummal hívjuk meg, akkor az előző
kimeneti értéket fogja használni (s.s.).
Például, tegyük fel, hogy egy olyan esetet fedezel fel, amit nem tudsz
hogyan kellene kezelni. Hagyományosan a program ezt úgy jelenti neked, hogy
nem zérus státusszal lép ki. Az awk programod is megteheti ezt,
ha az exit kifejezést egy nem zérus argumentummal használod.
Íme egy példa erre:
BEGIN {
if (("date" | getline date_now) <= 0) {
print "Can't get system date" > "/dev/stderr"
exit 1
}
print "current date is", date_now
close("date")
}
Go to the first, previous, next, last section, table of contents.