Programovací jazyk pro práci s textem: awk

Awk je programovací jazyk pro práci s textem. V textově orientovaném UNIXu jej používáme také pro automatickou konstrukci příkazů, příkazových souborů a předzpracování vstupních dat. Název Awk pochází ze jmen jeho autorů: Alfred V. Aho, Peter J. Weinberger a Brian W. Kernighan. Interpretem tohoto jazyka je příkaz (program) awk. Jeho verzí se však vyskytuje více. Nejvíce funkcí má zřejmě implementace awk z projektu GNU ( gawk) a verzi 3.1.x je následující text věnován. Tato implementace má všechny rysy podle POSIX 1003.2 a navíc některá rozšíření.

Použití awk

Příkaz se spouští následujícím způsobem:

awk program [soubory]
Program můžeme také číst ze souboru, potom zadáme:
awk -f soubor [soubory]
Program awk čte řádky buď ze zadaných souborů nebo ze standardního vstupu. Výstup směřuje na standardní výstup.

Struktura programu

Program pro awk se tvoří posloupností příkazů vzorek-akce a volitelně definic funkcí ve tvaru:

vzorek{akce - příkazy}
function jméno_funkce (seznam_parametrů) {příkazy}
V každém řádku čteném ze vstupu se hledá určený vzorek. Pokud se najde, provede se s řádkem zadaná akce. Poté, co se použijí všechny vzorky, přečte se ze vstupu další řádek a operace se opakují.

Jak vzorek, tak akce se smí vynechat. Nelze však vynechat obojí současně. Pokud není ke vzorku určena akce, potom se vyhovující řádek zkopíruje na výstup. Pro řádek vyhovující více vzorkům bude akce provedena vícekrát. Řádek nevyhovující žádnému ze zadaných vzorků se ignoruje.

Pokud vynecháme vzorek, potom se akce provede pro každý načtený řádek. Popis akce se musí uzavřít do složených závorek ' { }'. Tím se popis akce rozpozná od popisu vzorku.

Záznamy a položky

Vstup, který awk čte, dělíme do záznamů (records) ukončených oddělovačem záznamu. Implicitním oddělovačem záznamu je znak nového řádku. V tomto případě je záznamem jeden řádek. Číslo aktuálního záznamu awk udržuje v proměnné NR.

Každý zpracovávaný záznam se dělí do položek (field). Položky se implicitně oddělují bílým místem (mezera, tabulátor), lze však explicitně nastavit jinou hodnotu oddělovače položek. Na jednotlivé položky se odkazujeme $1, $2 atd. Údaj za znakem dolar je číslo (ne jenom číslice). Identifikátorem $0 se odkazujeme na celý záznam. Počet položek v aktuálním záznamu je uložen v proměnné NF.

Chceme-li změnit implicitní nastavení oddělovačů záznamů a položek, nastavíme novou hodnotu do proměnné: RS pro oddělovač záznamů a FS pro oddělovač položek. Obsah těchto proměnných můžeme změnit obecně na regulární výraz (v jiných verzích awk pouze na libovolný jeden znak). Oddělovač položek můžeme také nastavit na příkazovém řádku při spouštění awk volbou -Fc, kde c je oddělovač položek.

Je-li oddělovač záznamů prázdný, potom se jako oddělovač chápe prázdný řádek na vstupu. Oddělovači položek potom jsou znaky mezera, tabulátor a nový řádek.

V proměnné FILENAME je uloženo jméno aktuálního vstupního souboru ('-' v případě standardního vstupu).

Výstup

Nejjednodušší program, který opíše standardní vstup na standardní výstup, je následující:
... | awk '{ print }' | ...
Vzorek jsme vynechali, a proto se akce print provede pro všechny vstupující řádky. Akce print bez parametrů opíše celý řádek na výstup. Užitečnější bude vybrat si určité položky a tyto vypsat, např. první dvě položky v opačném pořadí:
{ print $2, $1 }
Takový zápis akce na příkazovém řádku spouštějícím awk musí být nutně uzavřen do dvojice apostrofů, aby nedošlo k expanzi dvojic znaků $1 a $2 na poziční parametry shellu, ale aby se v nezměněné podobě předaly awk.

Položky oddělené v zápisu akce print čárkou se na výstupu oddělí aktuálně nastavenou hodnotou oddělovače položek. Položky oddělené pouze mezerou se spojí bez oddělovače. Vyzkoušejme si:

{ print $2 $1 }

Akce print umí vypisovat i obsahy proměnných a textové řetězce, např.:

{ print "Číslo záznamu=" NR,
"Počet položek=" NF, $0 }
Takto zadaný program před kompletním záznamem vypíše číslo záznamu a počet položek v aktuálním záznamu.

Výstup můžeme rozdělit i do více výstupních souborů. Např. program:

{ print $1 >"soubor1";
print $2 >"soubor2" }
zapíše první položku do souboru soubor1 a druhou položku do souboru soubor2. Lze použít i zápis >>. Potom se do souboru přidává za konec. Jméno souboru může být proměnná, obsah zapisovaný do souboru může být konstanta. Můžeme tedy napsat např.:
{ print "nesmysl" >>$2 }
Jako jméno souboru se použije obsah druhé položky (pozor, nesmí být prázdná). V tomto příkladě bude počet řádků v jednotlivých souborech znamenat četnost slov ve druhém poli.

Podobně lze výstup z akce print předat rourou procesu. Např. poslat poštou na adresu 'zaznamenej':

{ print | "mail zaznamenej" }
Pokud si tento příklad vyzkoušíme, zjistíme, že se procesu předá celý vstup naráz, tj. nepředává se po jednotlivých záznamech a navíc se předá až po načtení konce vstupu.

Pomocí proměnných OFS a ORS můžeme samostatně nastavit oddělovače pouze pro výstup. Obsahem OFS se oddělí vypisované položky a obsahem ORS se oddělí vypisované záznamy.

Jazyk awk také poskytuje možnost formátovaných výstupů pomocí akce printf. Tato akce se zapisuje následujícím způsobem:

printf formát,výraz ,výraz, ...
Popisovačem formát sdělíme strukturu výstupu a prostřednictvím nadefinované struktury vypíšeme jednotlivé výrazy. V popisovači formát se používá stejná syntaxe jako v jazyce C. Uveďme si ve stručnosti možnosti:

Do řetězce formát vkládáme text, který se má vypsat. Na místa, kde se má vypsat výsledek výrazu, vložíme popisovač ve tvaru:

%příznakyšířkapřesnost typkonverze
Prvnímu popisovači (každý popisovač začíná vždy znakem %) se přiřadí výsledek prvního výrazu, druhému popisovači výsledek druhého výrazu atd. Jednotlivá pole popisovače mají tento význam (všechna pole vyjma konverze jsou nepovinná):
Na místě konverze se smějí použít tyto symboly:

Akce printf negeneruje žádné výstupní oddělovače. Všechny se musejí specifikovat ve formátu. Uveďme si příklad použití:

{ printf "Průměr=%8.2f, počet pokusů=%10ld\n", $1, $2 }
První položka se vytiskne jako číslo v pohyblivé řádové čárce celkem na 8 znaků se dvěma číslicemi za desetinnou tečkou. Druhá položka se vytiskne jako long integer na 10 znaků. Znak \n představuje nový řádek.

BEGIN a END

BEGIN a END jsou speciálními případy vzorků. Vzorek BEGIN specifikuje akci, která se má provést dříve, než se přečte první záznam vstupu. Naopak vzorek END popisuje akci, která se provede po zpracování posledního čteného záznamu. Tímto způsobem můžeme řídit zpracování před a po čtení záznamů.

Jako příklad uveďme nastavení specifického oddělovače položek a vytisknutí počtu načtených záznamů:

BEGIN { FS = ":" }
...zbytek programu...
END { print NR }
BEGIN musí být jako první vzorek (je-li uveden), END musí být posledním vzorkem.

Akce

Akce programu awk je posloupnost příkazů vzájemně oddělených novým řádkem nebo středníkem.

Proměnné, výrazy a přiřazení

Jazyk awk proměnné zpracovává podle kontextu: buď jako numerické hodnoty (v pohyblivé řádové čárce), nebo jako řetězce znaků. Řetězce se na numerické hodnoty převádějí podle potřeby. Potom např.
x = 1
je typicky numerický přiřazovací příkaz, ale v příkazu
x = "3" + "4"
se řetězce převedou na numerické hodnoty a proměnné x se přiřadí numerická hodnota 7. Řetězce, ze kterých nelze získat numerickou hodnotu, mají hodnotu 0.

Proměnná, které dříve nebyla přiřazena hodnota, má hodnotu nula. Interním proměnným awk se přiřazují hodnoty automaticky (viz dále). Proto např. program

{ s1 += $1; s2 += $2 }
END { print s1, s2 }
může k proměnné s1 přičítat. Proměnná interpretující se jako řetězec bez přiřazené hodnoty obsahuje prázdný řetězec.

Potřebujeme-li se ujistit, že proměnná bude chápána jako numerická, přičteme k ní hodnotu 0. Potřebujeme-li naopak proměnnou interpretovat jako řetězec, připojme k ní prázdný řetězec, např.

b = 12 ""

I když se numerické proměnné zpracovávají a ukládají v pohyblivé řádové čárce, desetinná tečka a číslice za ní se vypisují jenom tehdy, pokud je desetinná část nenulová. Číslo se na řetězec konvertuje podle obsahu proměnné CONVFMT voláním sprintf. Řetězec se na číslo konvertuje voláním atof.

Příklad


Na závěr první části pojednání o awk uveďme ilustrační příklad: Chceme awk použít na převod výstupu příkazu ls -l do klasického DOSovského tvaru výpisu adresáře, tj. ze tvaru:
celkem 692
-rw-r--r-- 1 root root 6608 srp 17 22:04 bind_view.html
-rw-r--r-- 1 root root 3016 srp 17 22:11 bind_view2.html
-rw-r--r-- 1 root root 690798 srp 17 21:45 Bind_9.pdf

do tvaru

bind_view.html 6608 srp 17 22:04

Sestavíme-li kolonu (rouru,pípu):


ls -l | grep -v ^total | awk -f dirp
potom pro awk  potřebujeme následující program v souboru dirp:
BEGIN {print "User is " ENVIRON["LOGNAME"]; print }
{printf "%-18s %10i %3s %2i %4s\n", $9, $5, $6, $7, $8;
suma = suma + $5 }
END {printf " %4i file(s)%11i bytes\n", NR, suma }

Příkazem grep -v ^total zrušíme nevýznamný řádek začínající slovem total. Pole ENVIRON popíšeme v následující části.

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.

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.

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

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.

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) }

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 [ elsepříkaz ]
while ( podmínka) příkaz
do příkazwhile (podmínka)
for ( výraz1; výraz2; výraz3) příkaz
for ( proměnnáinpole) 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 #.

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 (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 if a while 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"]

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

Interní proměnné awk

(...pokračování)

Vstupní a výstupní funkce

Následuje souhrnný přehled dosud uvedených i neuvedených vstupních a výstupních funkcí:
close(soubor)
Zavře soubor (nebo přesměrování).
getline
Načte další záznam do $0, nastaví se NF, NR, FNR.
getline <soubor
Načte další záznam do $0ze souboru soubor, nastaví se NF, NR, FNR.
getlinevar
Načte další záznam do var, nastaví se NF, NR, FNR.
getlinevar <soubor
Načte další záznam do var ze souboru soubor, nastaví se NF, NR, FNR.
next
Ukončí se zpracovávání běžného záznamu (řádku). Přečte se další záznam a zahájí se provádění prvního příkazu programu. Pokud se načte konec souboru, provede se blok END (je-li nějaký).
next file
Ukončí se zpracovávání aktuálně čteného souboru. Další řádek se čte už z dalšího souboru. Obnoví se FILENAME, FNR se nastaví na 1. Přečte se další řádek a zahájí se provádění prvního příkazu programu. Pokud se načte konec souboru, provede se blok END (je-li nějaký).
print
Vytiskne běžný záznam.
printseznam_výrazů
Vytiskne uvedený seznam výrazů.
printseznam_výrazů >soubor
Vytiskne uvedený seznam výrazů do souboru.
printfformát, seznam_výrazů
Vytiskne uvedený seznam výrazů podle zadaného formátu.
printfformát, seznam_výrazů >soubor
Vytiskne uvedený seznam výrazů podle zadaného formátu do souboru.
system(příkaz_systému)
Shell provede zadaný příkaz_systému a převezme se návratový kód.

Numerické funkce

V awk můžeme používat následující vestavěné aritmetické funkce.
atan2(y, x)
Vypočte arkustangens y/x a vrátí hodnotu v radiánech.
cos(výraz)
Vrátí kosinus výrazu v radiánech.
exp(výraz) Exponenciální funkce.
int(výraz) Odřízne desetinnou část.
log(výraz) Přirozený logaritmus.
rand() Náhodné číslo mezi 0 a 1.
sin(výraz) Sinus.
sqrt(výraz) Druhá odmocnina.
srand(výraz)
Zadaný výraz se použije na "rozmíchání" generátoru náhodných čísel. Není-li výraz uveden, potom se použije aktuální hodnota času. Funkce vrátí předchozí hodnotu výrazu.

Řetězcové funkce

asort(s [, d])
Vrátí počet prvků ve zdrojovém poli  s. Obsah s je setříděn za použití standardních pravidel gawk-u pro porovnávání hodnot, a  indexy setříděných hodnot sorted values pole s jsou nahraženy posloupností celých čísel počínaje od 1. Jestliže je specifikováno volitelné cílové pole d, pak je nejdříve s zkopírováno do d, pak je d setříděno, a indexy  zdrojového pole s jsou nezměněny.
gensub(r, s, h [, t] )
Prohledává řetězec t na splnění regulárního výrazu r. Pokud h je řetězec začínající g nebo G, pak nahradí všechny shody r řetězcem s. Jinak h je číslo udávající kolikátá shoda r se má nahradit. Pokud t není uvedeno,je místo něho použita proměnná $0. Posloupnost \n uvnitř nahrazujícího textu s, kde n je číslice od 1 do 9, může být užita k indikaci právě jen textu, který splňuje  n-tý závorkovaný podvýraz. Posloupnost \0 zastupuje celý splňující text, stejně jako znak &. Na rozdíl od sub() a gsub() je jako výsledek vrácen modifikovaný řetězec a původní řetězec je nezměněn.
gsub(r, s, t)
Každý podřetězec řetězce t vyhovující regulárnímu výrazu r se nahradí řetězcem s. Funkce vrací počet náhrad. Pokud nebyl zadán řetězec t, použije se $0.
index(s, t)
Vrátí index podřetězce t v rámci řetězce s nebo 0, pokud se podřetězec nenašel.
length(s)
Funkce vrátí délku řetězce s nebo řetězce $0, pokud jsme s nezadali.
match(s, r)
Vrátí se pozice uvnitř řetězce s, od které začíná podřetězec vyhovující RE r. Nenajde-li se, vrátí se 0. Funkce rovněž nastavuje proměnné RSTART a RLENGTH.
split(s, a, r)
Rozdělí řetězec s do jednorozměrného pole a podle RE r . Pokud r nezadáme, použije se obsah FS. Funkce v řetězci najde všechny výskyty oddělovače podle r. Tyto výskyty rozdělí řetězec na podřetězce a jednotlivé podřetězce se uloží do elementů pole a číslovaných od 1. Funkce vrátí počet podřetězců.
sprintf(formát, výrazy)
Funkce vytiskne výrazy podle zadaného formátu. Vrátí se výsledný řetězec.
strtonum(str)
Testuje str a vrací jeho numerickou hodnotu. Pokud str začíná úvodní 0, strtonum() předpokládá že str je osmičkové číslo. Pokud str začíná úvodní 0x nebo 0X, strtonum() předpokládá, že str je hexadecimální číslo.
sub(r, s, t)
Funkce se od gsub() liší tím, že se nahradí pouze první vyhovující řetězec.
substr(s, i, n)
Funkce vrací n-znakový podřetězec řetězce s začínající na pozici i. Pokud n vynecháme, vezme se zbytek řetězce s.
tolower(řetězec)
Vrací se řetězec se všemi velkými písmeny převedenými na malá písmena. Jiné znaky než velká písmena zůstanou beze změny.
toupper(řetězec)
Vrací se řetězec se všemi malými písmeny převedenými na velká písmena. Jiné znaky než malá písmena zůstanou beze změny.

Časové funkce

Program GNU awk poskytuje možnost doplňovat produkovaný text informací o datu a čase.
mktime(datespec)
Konvertuje datespec do časového razítka (time stamp = počet vteřin od 1.1.1970) ve stejném tvaru jako vrací systime(). datespec je řetězec tvaru YYYY MM DD HH MM SS[ DST]. Obsahem řetězce je  šest nebo sedm čísel reprezentujících úplný rok včetně století, měsíc od 1 do 12, den v měsíci od 1 do 31, hodinu dne od 0 do 23, minutu od 0 do 59, a vteřinu od 0 to 60, a volitelný příznak letního času. Hodnoty těchto čísel nemusí být uvnitř specifikovaného rozsahu; např. hodina zapsaná jako -1 znamená 1 hodinu před půlnocí. Je předpokládán Gregoriánský kalendář s počátkem v nule, kde rok  0 předchází roku 1 a rok -1 předchází roku 0. Čas je předpokládán v místní časové zóně. Pokud je příznak letního času kladný, předpokládá se letní čas; pokud je nula, předpokládá se stndardní čas; a pokud je záporný (defaultní), mktime() se pokouší zjistit zda je zadaný čas v letním čase. Pokud datespec neobsahuje dostatek elementů nebo je výsledný čas mimo rozsah, mktime() vrací hodnotu -1.
systime()
Funkce předává aktuální čas v počtu sekund od 1.1.1970 (v POSIX kompatibilních systémech).
strftime(formát, čas)
Funkce zformátuje údaj čas podle zadaného formátu. Hodnota čas musí být v takovém tvaru, jaký produkuje systime() . Pokud hodnotu čas vynecháme, uplatní se aktuální čas. Řetězec formát se zadává stejně jako ve stejnojmenném knihovním podprogramu.

Řetězec formát funkce strftime() obsahuje jak identifikaci časových údajů (začínají znakem %), tak i normální text - ten se opíše beze změn. Časové údaje jsou následující (uživatel by měl mít možnost konfigurovat údaje předávané touto funkcí podle národních zvyklostí):

Uveďme si příklad:

strftime("Dnes je %d. %m. %Y
a máme %H:%M hodin.")

Řetězcové konstanty

Řetězcové konstanty uvnitř programu pro awk jsou řetězce uzavřené do dvojic uvozovek. Uvnitř těchto řetězcových konstant můžeme používat tyto escape posloupnosti:

Výše uvedené escape posloupnosti se mohou použít i uvnitř jednoznakového RE reprezentujícího třídu znaků. Např. '/[ \t\f\n\r\v]/' vyhovuje všem znakům typu "bílé místo".

Speciální soubory

GNU verze awk při přesměrovávání výstupu příkazů print, printf a při čtení pomocí getline interně zpracovává následující speciální soubory. Tyto speciální soubory zprostředkují přístup k otevřeným popisovačům souborů zděděných od rodiče (zpravidla od shellu) nebo poskytnou informace o procesu.
/dev/pid - Přečtením tohoto souboru obdržíme číslo aktuálně běžícího procesu ukončené znakem nového řádku.
/dev/ppid - Přečtením tohoto souboru obdržíme číslo rodičovského procesu.
/dev/pgrpid - Přečtením tohoto souboru získáme skupinové ID aktuálně běžícího procesu.
/dev/user - Přečtením tohoto souboru obdržíme jeden záznam ukončený novým řádkem. Položky záznamu jsou odděleny mezerou. Položka $1 obsahuje uživatelské ID z volání getuid(), $2 obsahuje uživatelské ID z volání geteuid(), $3 obsahuje ID skupiny z getgid(), $4 je hodnota z getegid(). Případné další položky jsou hodnoty vrácené voláním getgroups(). Tato jména souborů jsou nyní zastaralá. Užijte pole PROCINFO k získání těchto informací.
/dev/stdin - Standardní vstup.
/dev/stdout - Standardní výstup.
/dev/stderr - Standardní chybový výstup.
/dev/fd/n - Soubor spojený s otevřeným popisovačem souboru číslo n.

Výstup na standardní chybový výstup můžeme poslat např. tímto příkazem:

print "Stala se chyba!" > "/dev/stderr"

Následující speciální jména souborů mohou být užita s |& ko-proces operátorem pro vytvoření TCP/IP síťových spojení.
/inet/tcp/
lport/rhost/rport - Soubor pro TCP/IP spojení z lokálního portu lport na vzdálený počítač rhost na vzdálený port rport. Užijte port 0 k jeho automatickému výběru systémem.
/inet/udp/
lport/rhost/rport - Podobné, ale užívá UDP/IP místo TCP/IP.
/inet/raw/
lport/rhost/rport - Rezervováno pro budoucí použití.

Volby GNU awk

Identifikátory voleb podle POSIX začínají jedním znakem minus, volby podle GNU začínají dvěma minusy. V rámci jedné volby -W lze zadat více slovních voleb, stejně tak lze zadat i více voleb -W na jednom řádku.
-F fs nebo --field-separator=fs
Nastavení oddělovače položek na vstupu (tj. určení implicitní hodnoty proměnné FS).
-v proměnná=hodnota nebo
--assign=proměnná=hodnota
Uvedené proměnné se přiřadí zadaná hodnota. Takto nastavené proměnné jsou k dispozici již během bloku BEGIN.
-f soubor nebo --file=soubor
Program se bude číst ze zadaného souboru. Těchto voleb může být na příkazovém řádku více.
-W compat nebo --compat
Program GNU awk se spustí v režimu kompatibility s klasickým awk . Všechna GNU rozšíření jsou vypnuta.
-W copyleft nebo -W copyright nebo --copyleft nebo --copyright
Na standardní chybový výstup se vypíše GNU copyright.
-W help nebo -W usage nebo --help nebo --usage
Na standardní chybový výstup se vypíše krátká nápověda k programu.
-W lint nebo --lint
Program upozorní na ty programové konstrukce, které nemusejí jiné implementace awk zpracovat.
-W posix nebo --posix
Zapne se kompatibilní režim s následujícími omezeními:

    sep=0mm

    Nerozpoznají se escape posloupnosti \x.

    Nerozpozná se synonymum func pro function.

    Na místo operátorů ^ a ^= se nesmějí použít operátory ** a **=.
-W source=program nebo --source=program
Jako argument této volby se zadává text programu pro awk. Význam spočívá v možnosti číst v rámci jednoho spuštění awk program jak ze souboru (např. knihovnu funkcí), tak i z příkazového řádku (vlastní krátký program). V tomto případě nelze v rámci volby -W zadat volbu další.
-W version nebo --version
Na standardní chybový výstup předá informaci o verzi aktuálního awk .
-- Oznamuje konec zadávání voleb.

Proměnná AWKPATH

Do proměnné prostředí AWKPATH můžeme obvyklým způsobem nastavit seznam cest k adresářům, které se budou procházet při hledání programů (tj. uvedených za volbou -f). Pokud proměnná neexistuje, použije se implicitní hodnota:
.:/usr/lib/awk:/usr/local/lib/awk

GNU awk rozšíření

Na závěr shrneme rozšíření GNU verze awk oproti definici POSIX (viz též volba -W compat):

Ilustrační příklady

Příklad 1:

Mějme textovou databázi předmětů, ze kterých si student při zápisu do semestru vybírá. Jednotlivé položky oddělujeme dvojtečkou. Učitel je v databázi jednoznačně identifikován svým přihlašovacím jménem. Pokud je více než jeden učitel, pak jsou jejich přihlašovací jména oddělena čárkou. Databáze nechť má tento tvar:


P000:3:zk:Architektura počítačů:brandejs
P004:2:zk:UNIX:brandejs
I011:2:zk:Sémantiky programovacích jazyků:
zlatuška

Úkol zní: vypsat obsah databáze v "čitelném" tvaru a převést přihlašovací jméno na příjmení a první písmeno křestního jména. Pro tento účel si vytvořme např. soubor logins s následujícím obsahem:


adelton:Jan:Pazdziora
brandejs:Michal:Brandejs
kas:Jan:Kasprzak
kron:David:Košťál
zlatuska:Jiří:Zlatuška

Pro převod přihlašovacího jména na příjmení pak použijeme jednorozměrné pole, kde indexem bude přihlašovací jméno a obsahem zkonstruovaná dvojice příjmení a křestního jména. Pole naplňujeme pouze jednou, a to v části BEGIN. Databáze předmětů nechť se načítá ze standardního vstupu.


... | awk -F':' 'BEGIN { while ( getline
<"logins" == 1 ) {
logins[$1]=sprintf("%s %1.1s.", $3, $2) } }
{ pocet=split($5,loginy,",")
for (i=1; i <= pocet; i++) {if (i == 1)
last = logins[loginy[i]]
else last = last ", " logins[loginy[i]]; }
printf("%-5s %-50.50s %1s %2s %s\n",$1,$4,
$2,$3,last) }'

Příklad 2:

Následujícím programem spočítáme počet všech různých slov v textu:


BEGIN { FS="[^a-zA-Z]" }
{ for (i=1;i<=NF;i++) words[$i] = "" }
END { delete words[""]
# prázdné položky nepočítáme
for (i in words) sum++
print "V textu bylo " sum " různých
slov"
}

Příklad 3:

A poslední vzorový program vykonává totéž co příkaz wc:

{words+=NF; chars+=1+length($0)}
END {print NR,words,chars}