Awk
O Awk
AWK je jazyk pro zpracování řetězců. Používá se na podobné věci jako sed, jen je to trochu více programovací jazyk.
SYNOPSIS
awk [option] {-f p_soubor|program} [soubor ...]
OPTIONS
- -f p_soubor
- Soubor s programem AWK
- program
- retezec, ktery obshuje program awk
- soubor
- Jmena zpracovananych souboru. Nejsou-li uvedeny, zpracovava se standardni vstup.
EXAMPLES
$ ps ax | awk '{print $1 " " $5}'
...
32536 ps
32537 awk
$ # vytiskne prvni a treti sloupec z /etc/passwd
$ # jako oddelovac pole se bere :
$ awk -- 'BEGIN {FS=":"} {print $1 " " $3}' </etc/passwd
...
wwwrun 30
petr 1000
tomcat 114
Struktura zpracovávaných souborů
Záznamy a pole
Implicitni oddelovac zaznamu ve zpracovavanych souborech je znak "novy radek" (zaznamem je tedy cela radka). Kazdy vstupni zaznam je dale rozdelen na pole. V normalnim pripade jsou pole od sebe oddelena mezerami nebo tabulatory, ale lze definovat i jinne oddelovace.
Cislo aktualniho zaznamu je ulozeno v promenne NR
.
Jednotliva pole jsou pristupna v programu awk pomoci promennych $1 (prvni pole), $2 (druhe pole) ….
V $0 je ulozeny cely vstupni zaznam (obvykle radka).
Struktura programu
Následující část popisuje strukturu skriptu AWK, která se píše
do souboru předávaného volbou -f
nebo se píše rovnou na příkazovou
řádku (do jednoduchych uvozovek).
Bloky programu
vzor {akce} [vzor {akce} ...]
- vzor
- Program se aplikuje pouze na radky, ktere odpovidaji vzoru (reg. vyraz). Vzor je nepovinny. V pripade, ze neni uveden, provede se akce pro vsechny radky. Radek nevyhovujici zadnemu vzoru se ignoruje.
- {akce}
- Akce je take nepovinna. Neni-li uvedena, radky vyhovujici danemu vzoru se jen vytisknou na standardni vystup (defaultni akce je {print})
Vzory
Jako vzor lze pouzit logicky vyraz nebo regularni vyraz. Operator ~
testuje, zda pole nebo
promenna vyhovuje regularnimu vyrazu. Operator !~
je negaci operatoru ~
,
tedy testuje na neshodu s regularnim vyrazem.
V logickych vyrazech je mozne pouzivat nasledujici relacni operatory:
Operátor | Význam |
---|---|
< | mensi nez |
<= | mensi nebo rovne |
== | rovno |
!= | neni rovno |
>= | vetsi nebo rovno |
> | vetsi nez |
|| | logicky soucet (nebo - or) |
&& | logicky soucin (a - and) |
vzor ? vzor1 : vzor0 | Pokud radka odpovida vzoru, vyhodnoti se jeste vzor1, jinak vzor0 |
Druhy vzorů
- { … }
- (bez vzoru) Vykona se pro vsechny radky
- BEGIN { … }
- Akce spojene s timto vzorem se vykonaji pred zahajenim ostatnich akci awk.
- END { … }
- Akce se provedou po ukoncini zpracovani vsech osatnich akci awk.
- /reg vyraz/ { …}
- Akce se provedou na zaznamech (radkach), ktere odpovidaji vzoru
- (logicky vyraz) { … }
- Akce se provedou, pokud se logicky vyraz vyhodnoti jako pravdivy
- vzor, vzor { … }
- Carka je operator rozsahu. awk zpracovava interaval radek, ktery zacina radkem vyhovujici prvnimu vzoru a konci radkem, ktery vyhovuji druhemu vzoru. Pote, co awk nalezne druhy vzor (dokonci zpracovavani rozsahu), opet zacina hledat prvni vzor.
Examples
- awk '$1~/^[Aa]/ {print}'
- Vybira vsechny radky, ve kterych prvni pole odpovida regularnimu vyrazu ^[Aa]
- awk '$1 < 5 ? $1 >1 : $1 > 8 {print}' cisla.txt
- Vybira radky, ve kterych, pokud je prvni sloupec mensi nez 5 a vetsi nez 1 nebo je vetsi nez 5 a vetsi nez 8. (Tj. napr. cisla 2,3,4,9,10)
Akce
Odkazy na pole v záznamu
Záznam je defaultně řádka (oddělovač záznamů je defaultně znak "nová řádka").
Oddelovac poli v zaznamu je defaultne mezera. Je ulozen ve specialni promenne FS, kterou je mozno nastavit na jinou hodnotu. Oddelovac poli na vystupu je ulozen v promenne OFS. (Pouziva se u funkce print, kde se argumenty oddeluji carkou - misto carky se pouzije oddelovac OFS).
- $1 $2 $3 …
- odkazy jednotlive pole
- $0
- cely zaznam (cela radka)
- NF
- pocet poli ({printf $1, $NF} vytiskne prvni a posledni pole oddelene mezerou)
Akce - telo awk programu
Akce je to, co je uvnitr spicatych zavorek {}.
Neni-li uvedena, predpoklada se {print} (tj. vypis celeho radku).
Akce se provede na kazdem radku, ktery vyhovi vzoru uvedenem pred akci.
Pokud neni vzor uveden, provede se na kazdou radku. Pokud je vzor BEGIN resp. END,
provede se pred zacatkem cteni radek, resp. po skonceni.
Uvnitr akce awk
lze standardni vystup presmerovat do souboru (>), pripojit k souboru
(>>) nebo spojit se vstupem jineho programu (|).
Je-li v {} vice prikazu, jsou od sebe oddeleny strednikem.
Komentar
Vše za znakem #
uvnitr akce az do konce radky je chapano jako komentar.
(Hodi se pro programy zapsane v souboru, na prikazove radce se vyuzije stezi).
Promenne
Promenne se deklaruji a inicializuji svym prvnim pouzitim. Awk ma nekolik zabudovanych promennych:
- NR
- cislo aktualniho zazamu
- $0
- aktualni zaznam (jako jedna promenna)
- N
- pocet poli v aktualnim zaznamu
- $1,$2..
- jednotliva pole v aktualnim zaznamu
- FS
- oddelovac vstupnich poli (implicitne mezera nebo tabulator)
- RS
- oddelovac vstupnich zazamu (implicitne "novy_radek" )
- OFS
- oddelovac vystupnich poli (implicitne mezera)
- ORS
- oddelovac vystupnich zazanamu (implicitne "novy radek")
- FILENAME
- jmeno aktualniho vstupniho souboru
Hodnoty RS, ORS, FS a OFS lze v programu zmenit.
FUNKCE
Awk ma definovano nekolik funkci pro praci s cisli a retezci:
- length(str)
- pocet znaku v argumentu str. Neni-li argument uveden, predpoklada se aktualni vstupni zaznam ($0)
- int(num)
- vraci celociselnou hodnotu num.
- index(str1,str2)
- vrati 0, pokud str2 neni obsazen v str1, jinak vrati pozici, v niz je umisten str2 v retezci str1. (prvni znak zacina jednickou, ne nulou)
- split(str,arr,del)
- ulozi prvky argumentu str, oddelene od sebe oddelovacem del do prvku pole arr[1]...arr[n], a vrati poecet prvku v poli.
- sprintf(fmt,args)
- argumenty args se zformatuji podle formatu fmt a vrati se vytvoreny retezec.
- substr(str,pos,len)
- vrati se podretezec retezce str zacinajici na pozici pos o delce len znaku.
- exp(x)
- exponencialni funkce.
- log(x)
- prirozeny logaritmus.
- sqrt(x)
- druha mocnina.
- atan2(y,x)
- arcus tangens podilu y/x
- cos(x)
- cosinus x
- sin(x)
- sinus x
- getline
- cte dalsi zaznam
- gsub(RE,nahr,[str])
- provadi globalni substituci vzoru RE retezcem nahr v retezci str; pokud argument str neni uveden, predpoklada se $0.
- rand
- nahodne cislo v intervalu 0 az 1 vcetne.
Spoustu dalších funkcí můžete najít v manuálové stránce k awk.
Funkce printf
Funkci printf
lze pouzit vsude tam, kde se pouzije funkce print
.
Umoznuje ridit format vystupu podobne, jako printf
z jazyka C.
printf "ridici_retezec" arg1, arg2, ..., argn
- "ridici_retezec"
- urcuje, jak se budou zobrazovat nalsedujici argumenty arg1 až argn.
Ridici retezec muze obsahovat:
metaznaky | vyznam |
---|---|
\" | " |
\\ | \ |
\n | prechod na zacatek noveho radku |
\t | tabulator |
\b | posun o znak zpet (doleva) |
\r | navrat na zacatek aktual. radku |
\f | prechod na novou stranku |
Dale muze "ridici_retezec" obsahovat specifikace konverze:
%[-][x][.y] konverzni_znak
- | znamena zarovnani zleva |
x | minimalni sirka pole |
.y | pocet mist vpravo od desetinne carky |
Konverzni znak muze byt nasledujici:
d | dekadicky |
e | exponencialni notace |
f | cislo s pohyblivou radovou carkou |
g | kratsi varianta z f nebo e |
o | osmickove cislo bez znamenka |
s | retezec znaku |
x | hexadecimalni cislo bez znamenka |
Operátory
operator | Význam |
---|---|
* | nasobeni |
/ | deleni |
% | zbytek po deleni |
+ | scitani |
= | prirazeni |
++ | pricteni hodnoty 1 k promenne, ktera predchazi operator |
-- | odecteni … |
+= | pricteni nasledujiciho vyrazu k promenne predchazejici operator |
-= | odecteni … |
*= | vynasobeni ... a ulozeni vysledku do promenne predchazejici operator |
/= | deleni promenne predchazejici operator nasledujicim vyrazem a ulozenim do promenne predchazejici operator |
%= | zbytek po deleni … |
Řídící struktury
Pro rizeni cinnosti lze vyuzivat ridici struktury, ktere jsou podobne jako ty v jazyku C.
if (podminka) prikaz1 else prikaz2
for (inicializace ridici promenne cyklu; podminka; zmena ridici promenne cyklu) prikaz
while (podminka) prikaz
- break
- ukoncuje cykl
- continue
- zacina dalsi iteraci cyklu
- next
- zacne se zpracovavat dalsi vstupni zaznam
- exit
- prejde se na vzor END
EXAMPLES
Pokud zaznam nezacina cislem, budeme zpracovavat dalsi zaznam (dalsi radku),
dokud se nenajde radka zacinajici cislem.
Program je ulozen v souboru program.awk
.
while ($1 !~ /^[0-9]/)
{
getline
}
print $0
}
Program na tisknuti pouze sudych poli:
i=1;
while(i++ <= NF)
{
if (i%2) {
getline
continue;
}
else print $0
}
}
Zaznamy zacinajici teckou se ignoruji:
Vytisteni poli zaznamu v obracenem poradi:
Definice uživatelské funkce
function jmeno_funkce(arg, ...) { prikazy }
- Volani funkce muze byt uvedene jeste pred vlastni definici
- Mezi jmenem funkce a levou zavorkou nesmi byt zadna mezera
- Je-li argumentem pole, predava se odkazem (ve funkci muzeme zmenit hodnotu prvku pole a tato zmena se projevi v poli vně tela funkce). Obycejne promenne se predavaji hodnotou - pracujeme s jejich kopii a vne funkce se jejich hodnota nemeni.
- return x; - nektere funkce mohou takto vracet hodnotu
- lokalni promenne jsou promenne odsazene v seznamu argumentu extra mezerou (divny, ale je to tak)
EXAMPLES
Definujeme funkci hledej
, ktera v poli jmena
hleda retezec ulozeny v
argumentu kdo
. Pokud retezec v poli nalezne (prave tento retezec), vrati jeho
index, jinak vrati hodnotu -1. Argument uk
se pouziva jako lokalni promenna.
jmena[0] = "Petr"
jmena[1] = "Tomas"
print $1, hledej($1, jmena)
}
function hledej(kdo,jmena, uk)
{
for(uk=0;jmena[uk];uk++)
if(index(jmena[uk],kdo)==1 && length(jmena[uk])==length(kdo))
return uk
return -1
}
Pokud index vrati hodnotu 1, retezec kdo je zacatkem retezce jmena[uk]. Pokud maji i stejnou delku, shoduji se.
Asociativni pole
Všechny proměnné typu array jsou v awk asociativní (indexované řetězci).
Prirazeni hodnoty prvku asociativniho pole se provadi obdobne, jako kdyz prirazujeme hodnotu nejake promenne:
print pole[index]
Speciální operátor in
se dá použít pro zjištění, zda je v poli nějaký index:
print pole["index"]
Existuje i specialni tvar prikazu for
, ktery iteruje pres asociativni pole:
print prvek
Prvek je promenna, ktera nabyva hodnoty kazdeho indexu pole. Pole neni setridene, proto neni mozne se spolehat na poradi prvku v poli.
mesic["Unor"]=28; \
mesic["Brezen"]=31; \
.
.
mesic["Prosinec"]=31 }
END { for(i in mesic) print i, "ma " mesic[i] "dnu" }'
Leden ma 31dnu
Unor ma 28dnu
.
.
Prosinec ma 31dnu
Brezen ma 31dnu
Examples
Vytiskne se predposledni a posledni pole kazdeho radku souboru data. Jednotliva pole budou navystupu oddelena dvojteckou.
Pokud radek obsahuje jen jedno pole, radek se zobrazi dvakrat oddelen dvojteckou: nejprve $0, potom $1.
Sectou se hodnoty prvniho pole ve vsech radcich souboru soubor.txt a nakonec se vytiskne prumerna hodnota tohoto pole.
Vytiskne vsechny radky ze souboru, ve kterych se prvni pole lisi od prvniho pole predchoziho radku.