\"/
\"/ \"/    

Programovací jazyk textových manipulací: awk (2)

Michal Brandejs, FI MU
Ročník VI - číslo 1, září 1995
Citace: M. Brandejs. Programovací jazyk textových manipulací: awk (2). Zpravodaj ÚVT MU. ISSN 1212-0901, 1995, roč. VI, č. 1, s. 8-11.
Tematické zařazení: Programy, nástroje
Článek je součástí seriálu Programovací jazyk textových manipulací: awk
 předchozí článek | následující článek 

8  Regulární výrazy

Na místě vzorku se mohou vyskytnout jak základní regulární výrazy (RE) podle definice v příkazu ed, tak i rozšířené regulární výrazy podle definice v příkazu grep -E. Regulární výraz se uzavírá do dvojice lomítek. Např. program

     /L.*x/

vypíše všechny řádky, které obsahují nejprve znak L a potom x. Hledání vyhovujícího vzorku můžeme omezit např. na určitou položku. Např. program

     $1 ~ /^[Ll].*x$/

vypíše ty řádky, jejichž první položka začíná písmenem L nebo l a končí písmenem x. Operátor !~ vybere ten řádek, který vyhovující vzorek neobsahuje.

9  Relační výrazy

Jazyk awk povoluje použití relačních operátorů <, >, ==, != , >= a <=. Např. program

     $2 > $1 + 99

vypíše ty řádky, jejichž druhá položka je alespoň o 100 větší než položka první. Aritmetické operátory se používají stejné jako v aritmetických expanzích shellu. Např. program

     NF % 2 == 0

vypíše všechny řádky se sudým počtem položek. Relační operátory se mohou používat jak pro aritmetické srovnávání, tak i pro porovnávání řetězců. Proto např. program

     $1 >= "s"

vybere ty řádky, jejichž první položka začíná znakem s, t, u atd.

10  Kombinace vzorků

Na místě vzorku se může vyskytnout i jejich kombinace spojená booleovskými operátory && (AND - logický součin), || (OR - logický součet) a ! (NOT - negace). Proto např. vzorek

     $1 >= "l" && $1 < "o" && $1 !~ /^l.*x$/

způsobí výpis řádku, jehož první položka začíná písmenem l až n a zároveň položka nezačíná l a zároveň nekončí x. Operátory && a || se vyhodnocují zleva doprava. Vyhodnocování se zastaví v okamžiku, kdy je výsledek vzorku jasný.

11  Interval určený vzorky

Vzorek, kterým se vybírá akce, se může skládat ze dvou vzorků. Potom levý vzorek určuje první řádek a pravý vzorek určuje poslední řádek, pro který se akce provede. Např. vzorek

     /start/,/stop/

vypíše všechny řádky od řádku vyhovujícího vzorku /start/ po řádek vyhovující vzorku /stop/. Např. program

     NR == 100, NR == 200

vypíše záznamy (řádky) 100 až 200.

12  Identifikátor položky jako proměnná

Identifikátory položek ($1, ...) požívají stejných vlastností jako proměnné. Mohou se používat jak v aritmetickém, tak i řetězcovém kontextu. Lze jim také přiřadit hodnotu. Proto lze napsat např.

     { $2 = NR; print }

nebo dokonce

     { $1 = $2 + $3; print $0 }

Odkazy na konkrétní položky se mohou také vyjádřit numerickým výrazem, např.

     { print $i, $(i+1), $(i+n) }

13  Příkazy pro řízení toku

Jazyk awk dovoluje použít příkazy pro řízení toku obvyklé u vyšších programovacích jazyků. Jde o tyto příkazové konstrukce:

     if (podmínka) příkaz [ else příkaz ]
while (podmínka) příkaz
do příkaz while (podmínka)
for (výraz1; výraz2; výraz3) příkaz
for (proměnná in pole) příkaz
break
continue
next
delete pole[index]
exit [ výraz ]
{ příkaz[; příkaz ... ] }

Z výše uvedených konstrukcí můžeme vytvořit např. tyto příklady:

     { if ($3 > 1000)
     $3 = "moc velké"
  print
}

Následující příklad vytiskne vždy jednu položku na jeden řádek:

     { i = 1
while (i <= NF) {
    print $i
    ++i
}}

V příkladu jsme si ukázali, že na místě příkazu smí být i více příkazů uzavřených do složených závorek. Následující příkaz provede totéž:

     { for (i = 1; i <= NF; i++) print $i }

První výraz znamená počáteční přiřazení, druhý výraz představuje podmínku a třetí výraz se opakovaně provádí.

Příkaz break okamžitě ukončí provádění cyklu while nebo for. Příkaz continue přejde ihned na novou iteraci cyklu.

Příkazem next přejdeme na zpracování dalšího řádku (záznamu) vstupu. Příkaz exit je totéž, co načtení konce vstupu (souboru).

Do programu pro awk lze vkládat komentáře. Řádek s poznámkou musí začínat znakem #.

14  Pole

Pole (arrays) se v awk předem nedeklarují. Jako příklad použití pole uveďme

     { x[NR] = $0 }

Tímto programem načteme celý vstup do jednorozměrného pole a zpracujeme jej až v akci náležející speciálnímu vzorku END.

Prvky pole můžeme indexovat také nenumerickými hodnotami, např. řetězci. Ukažme si opět příklad použití

     /modra/     { x["modra"]++ }
/cervena/   { x["cervena"]++ }
END         { print x["modra"],
              x["cervena"] }

Pole v awk mohou být obecně n-rozměrná. Jejich prvky se totiž ukládají tak, jak je tomu u asociativních pamětí. S prvkem je uložen i jeho index. V případě více prvkových položek se jednotlivé indexy od sebe oddělují oddělovačem \034 (tuto hodnotu lze změnit proměnnou SUBSEP, viz dále). Potom např.

     i = "A"; j = "B"; k = "C"
x[i,j,k] = "hello, world\n"

do paměti uloží index ve tvaru A\034B\034C. V příkazu for můžeme použít zvláštní operátor in následovně:

     for (proměnná in pole) ...

Operátor in v příkazu for zajistí, že proměnné se budou postupně přiřazovat všechny prvky pole. Prvky jsou přiřazovány obecně v náhodném pořadí. Pokud obsah proměnné změníme nebo pokud současně zpřístupňujeme i jiné prvky pole, nastane zřejmě chaos. Je-li pole vícerozměrné, můžeme pro uložení všech indexů (jako řetězce) použít jednu proměnnou.

Operátor in můžeme použít i v příkazech ifwhile ke zjištění, zda element určitého indexu se v poli nachází. Můžeme napsat

     if (hodnota in pole) print pole[hodnota]

V případě vícerozměrných položek používáme zápis např.

     if (("A","B","C") in x)
   print x["A","B","C"]

Prvky pole rušíme příkazem delete např. následovně:

     delete x["A","B","C"]

15  Funkce

Funkce nebyly do původního awk zahrnuty. Definují se tímto způsobem:

     function jméno(seznam_parametrů) { příkazy }

Při volání funkce se formální parametry nahradí aktuálními. Pole se předávají odkazem, ostatní proměnné hodnotou.

Lokální proměnné se ve funkcích definují dost zvláštním způsobem. Je to zapříčiněno faktem, že původní awk pojem lokální proměnné nezná. Lokální proměnné se definují v rámci seznamu_parametrů tak, že se uvedou na konci a oddělí se více mezerami, např.:

     function f(p, q,    a, b)
{ # proměnné a, b jsou lokální
                         ...  }
/abc/    { ... ; f(1, 2); ... }

Levá kulatá závorka musí následovat bezprostředně za jménem funkce (bez bílého místa). Tím se odstraní případné nejednoznačnosti syntaxe (možnost záměny s konkatenací).

Z funkce se smí volat jiná funkce a funkce smějí být rekurzivní. Na místě slova function se smí použít jenom func (rozšíření GNU verze).

16  Interní proměnné awk

ARGC
Obsahuje počet argumentů zadaných na příkazovém řádku při spouštění awk. Volby se do argumentů nepočítají.
ARGIND
Index do ARGV na právě zpracovávaný soubor.
ARGV
Pole argumentů z příkazového řádku. Pole se indexuje od 0 do ARGC-1. Obsah tohoto pole můžeme měnit a tím řídíme výběr souborů ke zpracování.
CONVFMT
Formát pro konverzi čísel, implicitně '%.6g'.
ENVIRON
Pole obsahující kopii proměnných prostředí. Indexem je jméno proměnné; vyzkoušejte např. ENVIRON["HOME"]. Obsah jednotlivých prvků pole můžete měnit. Tato změna se však neprojeví na proměnných prostředí předávaných procesům, které jsou z awk spouštěny (např. symbolem |). Tato vlastnost se může v dalších verzích změnit.
ERRNO
Tato proměnná obsahuje řetězec popisující chybu, která vznikla během poslední operace getline, přesměrování a zavření.
FILENAME
Jméno právě zpracovávaného souboru nebo '-' pro standardní vstup. Proměnná FILENAME je uvnitř bloku BEGIN nedefinována.
FNR
Číslo vstupního záznamu v rámci aktuálního souboru.
FS
Oddělovač položek na vstupu; implicitně mezera.
IGNORECASE
Proměnná řídí zpracování malých a velkých písmen ve všech operacích s regulárními výrazy. Obsahuje-li proměnná IGNORECASE nenulovou hodnotu, potom se ignorují rozdíly mezi malými a velkými písmeny. Implicitně proměnná obsahuje nulu.
NF
Počet položek aktuálně zpracovávaného záznamu.
NR
Počet načtených záznamů.
OFMT
Výstupní formát čísel, implicitně '%.6g'.
OFS
Oddělovač položek na výstupu; implicitně mezera.
ORS
Oddělovač záznamů na výstupu; implicitně nový řádek.
RS
Oddělovač záznamů na vstupu; implicitně nový řádek. Z řetězce RS se akceptuje pouze první znak (což se může v budoucích verzích změnit). Pokud RS obsahuje prázdný řetězec, potom se záznamy oddělují prázdným řádkem a položky novým řádkem bez ohledu na nastavení FS.
RSTART
Index prvního vyhovujícího znaku vraceného funkcí match(). Pokud žádný nevyhovuje, potom proměnná obsahuje 0.
RLENGTH
Délka vyhovujícího řetězce vraceného funkcí match(). Pokud žádný nevyhovuje, potom proměnná obsahuje -1.
SUBSEP
Znak oddělující jednotlivé indexy při ukládání indexu prvku vícerozměrného pole. Implicitně \034.
(... pokračování)
Zpět na začátek
ÚVT MU, poslední změna 14.11.2011