Programovací jazyk textových manipulací: awk (3)
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
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.
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ů ^ 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.
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):
- Escape posloupnosti \x
- Funkce systime() a strftime()
- Rozpoznávání jmen zvláštních souborů
- Proměnné ARGIND, ERRNO, AWKPATH a IGNORECASE
- Příkaz 'next file'
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} |
ÚVT MU, poslední změna 14.11.2011