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


Vezérlésátadó kifejezések a tevékenységekben

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.

Az 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.

A while kifejezés

A 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.

A 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.

A 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.

A 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.).

A 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.).

A 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.

A 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.

Az 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.