\"/
\"/ \"/    

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

Michal Brandejs, FI MU
Ročník VI - číslo 2, listopad 1995
Citace: M. Brandejs. Programovací jazyk textových manipulací: awk (3). Zpravodaj ÚVT MU. ISSN 1212-0901, 1995, roč. VI, č. 2, s. 4-8.
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 

17  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 $0 ze souboru soubor, nastaví se NF, NR, FNR.
getline var
Načte další záznam do var, nastaví se NF, NR, FNR.
getline var <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.
print seznam_výrazů
Vytiskne uvedený seznam výrazů.
print seznam_výrazů >soubor
Vytiskne uvedený seznam výrazů do souboru.
printf formát, seznam_výrazů
Vytiskne uvedený seznam výrazů podle zadaného formátu.
printf formá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.

18  Numerické funkce

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.

19  Řetězcové funkce

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

20  Časové funkce

Program GNU awk poskytuje možnost doplňovat produkovaný text informací o datu a čase.

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í):

%a    Zkratka dne v týdnu.
%A Plné jméno dne v týdnu.
%b Zkratka názvu měsíce.
%B Plný název měsíce.
%c Preferovaný způsob zápisu data a času.
%d Den v měsíci (desítkově).
%H Hodina ve 24hodinovém cyklu (00 až 23).
%I Hodina ve 12hodinovém cyklu (01 až 12).
%j Den v roce (001 až 366).
%m Měsíc (01 až 12).
%M Minuta desítkově.
%p AM nebo PM.
%S Sekunda.
%U Týden v roce (desítkově). První týden začíná první nedělí v roce.
%W Týden v roce (desítkově). První týden začíná prvním pondělím v roce.
%w Den v týdnu (desítkově). Neděle je den 0.
%x Preferovaný způsob zápisu data bez času.
%X Preferovaný způsob zápisu času bez data.
%y Rok bez století (00 až 99).
%Y Rok včetně století.
%Z Jméno nebo zkratka časové zóny.
%% Znak procento.

Uveďme si příklad:

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

21  Ř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:

\\    Znak obrácené lomítko.
\a Znak 'zvonek' - pípne (alert).
\b Backspace - návrat o znak zpět.
\f Nová stránka (form feed).
\n Nový řádek (new line).
\r Návrat vozíku (carriage return).
\t Horizontální tabulátor.
\v Vertikální tabulátor.
\xhex Znak zapsaný šestnáctkově, např. \x1B je znak ESCAPE.
\oct Znak zapsaný osmičkově, např. \033 je znak ESCAPE.
\c Literál znaku c.

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

22  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().
/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"

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

-Ffs   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:
  • Nerozpoznají se escape posloupnosti \x.
  • Nerozpozná se synonymum func pro function.
  • Na místo operátorů ^^= se nesmějí použít operátory ****=.
-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.

24  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

25  GNU awk rozšíření

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

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

Zpět na začátek
ÚVT MU, poslední změna 14.11.2011