Linux: Kniha kouzel, 2.15 (1. března 2025)
Veškerá moc příkazové řádky/příkazového řádku přehledně, pro začátečníky i pokročilé

3. AWK

Vývoj vanilkové příchuti Linuxu: Knihy kouzel byl 1. března 2025 ukončen. Tento text je zachován jako historický, ale chyby již nejsou opravovány. Odnože projektu pod kompatibilní licencí jsou vítány.

1. Úvod

GNU AWK je skriptovací nástroj pro řádkově orientované zpracování textových souborů. Nabízí podstatně více možností než „sed“, ale ve srovnání s Perlem zůstává velmi omezený (např. jeho jedinou datovou strukturou je asociativní pole), což ho činí velmi vhodným pro začátečníky, ale nedostačujícím pro komplikovanější projekty. Syntaxe AWK je (zvlášť ve srovnání s Perlem) elegantní a umírněná.

Skript AWK se skládá ze sekvence takzvaných „vzorků“ (podmínek) a k nim příslušejících bloků příkazů. AWK rozdělí vstupní soubory po řádcích (záznamech), každý záznam rozdělí na sloupce a pro každý záznam postupně prochází celý skript a testuje jeden vzorek po druhém. Když vzorek vyhoví, příslušný blok příkazů se vykoná, jinak se přeskočí. Kromě toho AWK spouští i několik dalších (zvláštních) iterací, kdy se vykonají bloky označené určitým klíčovým slovem (např. BEGIN).

Vzorek nebo blok příkazů je dovoleno vynechat; vynecháme-li vzorek, blok příkazů se vykoná pro každou řádku (ale ne ve speciálních iteracích); vynecháme-li blok příkazů, automaticky se doplní „{print $0}“.

Nejčastějším tvarem vzorku je podmínka tvořená pouze literálem regulárního výrazu (např. „/^a/“), taková podmínka se (nejen v tomto kontextu) automaticky rozšíří na výraz „($0 ~ /^a/)“, tedy porovnání načteného řádku s uvedeným regulárním výrazem.

Pozor! V AWK se všechny druhy indexů a číslování číslují vždy od jedničky, nikdy od nuly!

2. Definice

  • Vzorek (pattern) je podmínka, která určuje, zda se daný blok příkazů má v dané iteraci skriptu provést. Podmínkou může být obecný výraz nebo jedno z klíčových slov, která identifikují speciální iterace.
  • Záznam (record) je typicky řádka vstupního souboru. Způsob ukončení záznamu ve vstupních souborech určuje zvláštní proměnná „RS“ (record separator), jejíž výchozí hodnota je "\n".
  • Záznam se po načtení rozdělí do sloupců (fields). Způsob oddělení záznamů se nastavuje zvláštní proměnnou „FS“ (field separator), jejíž výchozí hodnotou je mezera, která má zvláštní význam odpovídající regulárnímu výrazu „\s+“.
  • Regulární výraz může být ve skriptu AWK zadán buď jako literál do lomítek, např. „/^a/“, nebo jako dynamický regulární výraz, což je jakýkoliv řetězec či řetězcový výraz zadaný v místě, kde se očekává regulární výraz. Tyto dva způsoby zadání jsou většinou víceméně rovnocenné, ale liší se požadavky na odzvláštnění (v literálu musíte odzvláštnit všechny výskyty znaku „/“, a to i uvnitř hranatých závorek) a tím, že dynamický regularní výraz se nikdy automaticky nedoplní o prefix „$0 ~“, zatímco literál to dělá skoro vždy.
  • Jmenný prostor (namespace) je oblast platnosti pro globální identifikátory. Výchozí je jmenný prostor „awk“, také zvaný globální jmenný prostor. Jmenné prostory neplatí pro identifikátory tvořené pouze velkými písmeny anglické abecedy (např. „ABC“ nebo „PROMENNA“) a pro klíčová slova (např. „sin“ nebo „if“). Rovněž se nevztahují na lokální identifikátory (názvy parametrů funkcí).

3. Zaklínadla: Hlavní

3/1 Vzorky a bloky příkazů

@podmíněné vykonávání (obecně)#1
podmínka [{blok příkazů}]
@podmíněné vykonávání (příklady)#2
PROMENNA == 1 && /^X/ {ZAJIMAVY_RADEK = $0}
$1 ~ /ABC/ {print $2}
priznak {next}
$0 != "xyz" {print "ne-XYZ:";print $0;}
!/^#/
length($0) > 5 || /^%/ {print "Řádka " FNR " podmínku splnila."}
@vykonat blok příkazů pro každou řádku#3
{blok příkazů}
@před otevřením prvního souboru#4
BEGIN {blok příkazů}
@před definitivním ukončením skriptu#5 (1)
END {blok příkazů}
@po otevření souboru (ale před načtením prvního řádku)#6
BEGINFILE {blok příkazů}
@po zpracování poslední řádky souboru#7 (2)
ENDFILE {blok příkazů}
@řádky „od“ až „do“ včetně hranic#8
podmínka od,podmínka do [{blok příkazů}]
@řádky „od“ až „do“ kromě hranic#9
{if (!pomocná_proměnná) {pomocná_proměnná = podmínka od} else if (podmínka do) {pomocná_proměnná = 0} else {blok příkazů}}

3/2 Skalární proměnné

@přečíst hodnotu proměnné (z aktivního jmenného prostoru/z globálního/z konkrétního)#1
název_proměnné
awk::název_proměnné
jmenny_prostor::název_proměnné
@přiřadit hodnotu proměnné#2
[jmenny_prostor::]název_proměnné = hodnota
@získat hodnotu proměnné prostředí (obecně/příklad)#3
ENVIRON[řetězec-s-názvem-proměnné]
ENVIRON["PATH"]
@přiřadit hodnotu proměnné prostředí (obecně/příklad)#4
ENVIRON[řetězec-s-názvem-proměnné] = řetězec
ENVIRON["PATH"] = "/bin:/usr/bin";
@nepřímý přístup k proměnné (příklad)#5
[jmenny_prostor::]nazev_promenne = "hodnota";
UKAZATEL = "[jmenny_prostor::]nazev_promenne";
print SYMTAB[UKAZATEL];
SYMTAB[UKAZATEL] = "nova hodnota"

3/3 Asociativní pole

@přečíst hodnotu prvku pole#1
[jmenny_prostor::]pole[index]
@přiřadit hodnotu prvku pole#2
[jmenny_prostor::]pole[index] = hodnota
@existuje prvek pole?#3
index in [jmenny_prostor::]pole
@smazat z pole jeden prvek/všechny prvky#4
delete [jmenny_prostor::]pole[index];
delete [jmenny_prostor::]pole;
@počet prvků#5
length([jmenny_prostor::]pole)
@zkopírovat celé pole#6
delete cílové_pole;
for (pomocná_proměnná in pole) {cílové_pole[pomocná_proměnná] = pole[pomocná_proměnná]}
@je proměnná pole?#7 (3)
isarray(proměnná)

3/4 Asociativní pole: řazení

Poznámka k řazení asociativních polí: výsledkem řazení asociativního pole je vždy pole indexované celými čísly od 1 do návratové hodnoty řadicí funkce.

V následujících příkazech: „typ“ může být „num“ (řadit jako čísla) nebo „str“ (řadit jako řetězce, ale podle pozice znaků ve znakové sadě Unicode); „pořadí“ může být „asc“ (vzestupně) nebo „desc“ (sestupně).

@seřadit hodnoty podle klíčů/podle hodnot/uživatelskou funkcí#1 (4)
asort(pole, cílové_pole, "@ind_typ_pořadí")
asort(pole, cílové_pole, "@val_typ_pořadí")
asort(pole, cílové_pole, "jméno_funkce")
@seřadit klíče podle klíčů/podle hodnot/uživatelskou funkcí#2
asorti(pole, cílové_pole, "@ind_typ_pořadí")
asorti(pole, cílové_pole, "@val_typ_pořadí")
asorti(pole, cílové_pole, "jméno_funkce")
@příklad řazení#3
pocet_jmen = asort(prostor::jmena, prostor::serazena_jmena, "@val_str_asc");

3/5 Podmínky, cykly a přepínač

@podmínka if#1
if (podmínka) příkaz-nebo-blok [else příkaz-nebo-blok]
@cyklus while#2
while (podmínka) příkaz-nebo-blok
@cyklus for#3
for ([inicializace]; [podmínka]; [iterace]) příkaz-nebo-blok
@cyklus foreach#4 (5)
for (proměnná in pole) příkaz-nebo-blok
@přepínač switch#5 (6)
switch (skalární-výraz) {
[[case konstantní-hodnota:] [default:] příkazy]
}
@cyklus do-while (alternativy)#6
do { příkazy } while (podmínka);
do příkaz; while (podmínka);

3/6 Řízení toku

@opustit nejvnitřnější cyklus (for, while, do) nebo přepínač (switch)#1
break;
@skočit na podmínku nejvnitřnějšího cyklu (for, while, do)#2
continue;
@přejít na zpracování dalšího řádku#3
next;
@přejít na zpracování dalšího souboru#4 (7)
nextfile;
@přejít na průchod END („ukončit skript“)#5
exit [návratová-hodnota-programu];
@vypsat chybovou zprávu a skončit s chybou#6
print chybová-zpráva-řetězec > "/dev/stderr"
exit 1;

3/7 Dělení záznamů na sloupce

Poznámka: Dělení záznamů na sloupce určují proměnné FS, FPAT a FIELDWIDTHS.

@dělit sloupce libovolnou sekvencí bílých znaků#1
[FPAT = FIELDWIDTHS = "";] FS = " ";
@dělit sloupce tabulátorem#2
[FPAT = FIELDWIDTHS = "";] FS = "\t";
@dělit sloupce regulárním výrazem#3
[FPAT = FIELDWIDTHS = "";] FS = "regulární výraz";
@zapnout/vypnout režim sloupců pevné šířky#4 (8)
FIELDWIDTHS = "[[kolik-přeskočit:]šířka-dalšího-sloupce ][kolik-přeskočit:]šířka-posl-sloupce"
FIELDWIDTHS = ""
@režim sloupců pevné šířky (příklady)#5
FIELDWIDTHS = "5 2 7"⊨ $1 = „12345“ $2 = „67“ $3 = „89ABCDE“
FIELDWIDTHS = "1:3 2:2 1:*"⊨ $1 = „234“ $2 = „78“ $3 = „ABCDEF“
@vypnout dělení na sloupce#6
FS = RS; FPAT = FIELDWIDTHS = "";
@každý znak jako samostatný sloupec#7
FS = "";
@dělit sloupce výhradně mezerou#8
FS = "[ ]";
@sloupce ze shod s regulárním výrazem (zapnout/vypnout)#9
FPAT = "neprázdný regulární výraz";
FPAT = "";

3/8 Speciální proměnné

@načtená řádka (bez oddělovače záznamu/s oddělovačem záznamu)#1
$0
$0 RT
@číslo řádky v souboru/celkově#2 (9)
FNR
NR
@sloupec načtené řádky (obecně/příklady...)#3
$číselný-výraz
$2
$12
$(NF - 1)
@název/index právě načítaného souboru#4 (10)
FILENAME
ARGIND
@počet sloupců v načteném řádku#5 (11)
NF
@výstupní oddělovač sloupců/záznamů příkazu print#6 (12)
OFS = "[řetězec]"
@vstupní oddělovač záznamu (jeden znak/regulární výraz)#7 (13)
RS = "znak"
RS = "regulární výraz"
@hodnota posledního sloupce načteného řádku#8
$NF
@počet souborů, které mají být (podle příkazové řádky) načteny jako vstupní#9 (14)
ARGC - 1
@N-tý (od 1) vstupní soubor, jak je zadán na příkazovém řádku#10
ARGV[N]

3/9 Ostatní

@komentář#1 (15)
#libovolný obsah až do konce řádky

4. Zaklínadla: Výstup, vstup a interakce s bashem

4/1 Příkazy výstupu

@příkaz print#1 (16)
print výraz[, další-výraz] [přesměrování-výstupu];
@funkce printf#2 (17)
printf(formátovací-řetězec[,výraz]) [přesměrování-výstupu];

4/2 Uzavření vstupu/výstupu

@uzavřít soubor otevřený ke čtení či zápisu#1 (18)
close("řetězec/reprezentující/soubor")
@uzavřít čtení výstupu příkazu#2
close("řetězec reprezentující příkaz")
@uzavřít zápis na vstup příkazu#3 (19)
close("řetězec reprezentující příkaz")
@vyprázdnit vyrovnávací paměť zápisu (soubor/standardní výstup)#4
fflush("řetězec/reprezentující/soubor")
fflush("/dev/stdout")

4/3 Bash

@vykonat příkaz interpretem „/bin/sh“ a vrátit jeho návratovou hodnotu#1
system(řetězec)

4/4 Přesměrování výstupu

Poznámky k přesměrování výstupu: Prvním zápisem do souboru, který ještě není otevřen, se tento soubor automaticky otevře pro zápis a zůstane otevřený pro další zápisy, dokud ho neuzavřete funkcí close() nebo do konce programu. Analogicky platí, že prvním zápisem na vstup dosud nespuštěného příkazu se tento příkaz spustí a další zápisy směřují na vstup téže instance příkazu, dokud spojení neuzavřete funkcí „close()“.

Pokud soubor existuje, při otevření se jeho obsah smaže; pokud chcete přidávat na konec souboru, použijte místo operátoru „>“ operátor „>>“ (princip je stejný jako v bashi).

@výstup do souboru (příklad)(print/printf)#1
print "A:", A > "../seznam.txt";
printf("%s: %d\n", I, POLE[I]) > "hodnoty.txt";
@poslat na (standardní) vstup jiného příkazu (print/printf)#2 (20)
print parametr[, další parametr] | "řetězec s příkazem" ;
printf(formátovací-řetězec[,parametr]) | "řetězec s příkazem" ;
@zapsat na vstup jiného příkazu (příklad)#3
print I, S, "." | "sort -n";
@zapsat na standardní chybový výstup#4
print parametry > "/dev/stderr";
printf(parametry) > "/dev/stderr";
@zapsat do souboru jeden znak (přepsat/připojit)#5
printf("%s", "znak") > "řetězec/s/cestou/souboru")

4/5 Přesměrování vstupu

Poznámky k přesměrování vstupu: Prvním čtením ze souboru, který ještě není otevřen, se tento soubor automaticky otevře pro čtení a zůstané otevřený pro čtení dalších řádků, dokud ho neuzavřete funkcí close(). Analogicky platí, že čtení z příkazu, který ještě nebyl spuštěn, ho spustí a další čtení čtou z výstupu téže instance, dokud spojení neuzavřete funkcí „close()“.

@přečíst řádku ze souboru#1
[if (]getline [PROMĚNNÁ] < "řetězec/s/cestou/souboru"[) tělo příkazu if]
@přečíst jeden znak ze souboru#2 (21)
RS = "(.)";
if (getline < "řetězec/s/cestou/souboru") {{proměnná} = RT}
@přečíst celý soubor do zadané proměnné#3
normalni_RS = RS; RS = "^$"; PROMĚNNÁ = "";
getline PROMĚNNÁ < "řetězec/s/cestou/souboru";
RS = normalni_RS;
[close("řetězec/s/cestou/souboru");]
@načíst řádku z výstupu příkazu#4
[if (]"příkaz" | getline [PROMĚNNÁ]) tělo příkazu if

4/6 Koprocesy

@zapsat na standardní vstup koprocesu (alternativy)#1
příkaz print |& koproces;
@přečíst řádek z výstupu koprocesu#2
[if (]koproces |& getline [PROMĚNNÁ][) tělo příkazu if]
@uzavřít jen vstup koprocesu#3 (22)
close(koproces, "to");
@vyčkat na ukončení koprocesu#4 (23)
close(koproces)

4/7 Informace o procesu AWK

@PID procesu gawk/rodičovského procesu#1
PROCINFO["pid"]⊨ 7034
PROCINFO["ppid"]⊨ 4052
@verze GNU awk#2
PROCINFO["version"]⊨ 5.0.1

5. Zaklínadla: Funkce

5/1 Uživatelské funkce

@definovat funkci (volitelně s lokálními proměnnými)#1
function název funkce([první-parametr[,další-parametry]][,   lokální-proměnná[, další-lokální-proměnná]]) blok příkazů
@volání funkce#2
název_funkce([parametr[, další parametr]])
@nepřímé volání funkce#3
@proměnná([parametr[, další parametr]])

5/2 Řetězcové funkce (regulární výrazy)

Poznámka k řetězci náhrady: V tomto řetězci je nutno odzvláštnit znaky „\“ a „&“, protože mají speciální význam: Funkce sub(), gensub() a gsub() za neodzvláštněný znak „&“ dosadí text shody s nahrazovaným regulárním výrazem. Funkce „gensub()“ navíc za značky „\1“ až „\9“ (do řetězce nutno zadávat jako "\\1" atd.) dosadí text číslovaného záchytu (podřetězec odpovídající seskupení v regulárním výrazu).

@vyhovuje/nevyhovuje regulárnímu výrazu?#1
řetězec ~ regulární-výraz
řetězec !~ regulární-výraz
@nahradit první výskyt/N-tý výskyt/všechny výskyty regulárního výrazu v proměnné#2
sub(regulární výraz, řetězec-náhrady, proměnná)⊨ počet náhrad (0, nebo 1)
proměnná = gensub(regulární výraz, řetězec-náhrady, N, proměnná)⊨ řetězec po náhradě (nezměněný, pokud k náhradě nedošlo)
gsub(regulární výraz, řetězec-náhrady, proměnná)⊨ počet náhrad
@nahradit první výskyt/N-tý výskyt/všechny shody v $0#3
sub(regulární výraz, řetězec-náhrady)⊨ počet náhrad (0, nebo 1)
$0 = gensub(regulární výraz, řetězec-náhrady, N)⊨ řetězec po náhradě (nezměněný, pokud k náhradě nedošlo)
gsub(regulární výraz, řetězec-náhrady)⊨ počet náhrad
@nahradit první výskyt/N-tý výskyt/všechny výskyty regulárního výrazu v řetězci#4
gensub(regulární výraz, řetězec-náhrady, 1, řetězec)
gensub(regulární výraz, řetězec-náhrady, N, řetězec)
gensub(regulární výraz, řetězec-náhrady, "g", řetězec)
@najít a vypsat první shodu s regulárním výrazem#5 (24)
if (match(řetězec, regulární-výraz)) {
print substr(řetězec, RSTART, RLENGTH);
}
@najít všechny shody s regulárním výrazem a sestavit z nich číslované pole#6 (25)
patsplit(řetězec, pole, regulární-výraz [,pole-pro-oddělovače])⊨ počet shod (např. „3“)
@rozdělit řetězec do pole, oddělovač je definovaný regulárním výrazem#7
split(řetězec, pole, regulární-výraz[,pole_pro_oddělovače])
@příklad: v řetězci „a=15:b=79“ v proměnné „x“ vyměnit čísla#8
x = gensub(/^a=([0-9]+):b=([0-9]+)$/, "a=\\2:b=\\1", 1, x);⊨ a=79:b=15

5/3 Řetězcové funkce (základní)

@spojit dva řetězce (konkatenace)#1
jeden-řetězec druhý-řetězec
@získat podřetězec podle pozice#2
substr(řetězec, počáteční-pozice[, maximální-délka])
@najít pozici prvního výskytu podřetězce#3 (26)
index(řetězec, hledaný-podřetězec)
@zjistit délku řetězce#4
length(řetězec)
@rozdělit řetězec do pole (podle FS/určitým znakem)#5
split(řetězec, pole)
split(řetězec, pole, "znak"[,pole_pro_oddělovače])
@naformátovat řetězec (funkce sprintf známá z jazyka C)#6
sprintf(formátovací-řetězec[, parametr])
@převod na malá písmena/velká písmena#7 (27)
tolower(řetězec)
toupper(řetězec)
@sekvence více výskytů téhož znaku v řetězci nahradit jeho jedním výskytem#8

5/4 Konverze číselných soustav

@desítkové číslo na hexadecimální/hexadecimální na desítkové#1
sprintf("[0x]%x", číslo)
strtonum("0xhex-číslo")
@desítkové číslo na osmičkové/osmičkové na desítkové#2
sprintf("[0]%o", číslo)
strtonum("0osmičkové-číslo")

5/5 Číselné funkce

@absolutní hodnota#1
x >= 0 ? x : -x
@zaokrouhlit desetinné číslo na nejbližší celé číslo/k nule/jen oříznout desetinnou část#2
číslo >= 0 ? int(číslo + 0.4999999) : int(číslo - 0.4999999)
číslo >= 0 ? int(číslo) : -int(-číslo)
int(hodnota)
@vygenerovat pseudonáhodné celé číslo 0 <= y < maximum#3 (28)
int(rand() * maximum)
@vygenerovat pseudonáhodné celé číslo 0 <= y < 4 294 967 296#4
65356 * int(65536 * rand()) + int(65536 * rand())
@nastavit počáteční „semínko“ generátoru pseudonáhodných čísel (na hodnotu/podle času)#5
srand(hodnota-semínka)
srand()
@vygenerovat pseudonáhodné desetinné číslo 0 <= y < 1#6
rand()
@druhá odmocnina/druhá mocnina#7
sqrt(x)
x^2
@arcus tangens y / x#8
atan2(y, x)
@sinus/kosinus/tangens/contangens#9
sin(x)
cos(x)
sin(x) / cos(x)
cos(x) / sin(x)
@přirozený logaritmus / e na x-tou#10
log(x)
exp(x)

5/6 Práce s časem

@aktuální čas (jako časová známka Unixu)#1
systime()
@zformátovat čas#2 (29)
strftime(formát,časová-známka-Unixu[, 1])

5/7 Pokročilé konstrukce

@přepnout se do jmenného prostoru/do globálního jmenného prostoru#1 (30)
@namespace "jmenný_prostor"
@namespace "awk"
@vložit kód z jiného zdrojového souboru#2 (31)
@include "cesta/k/souboru.awk"
@implementovat načítání řádek rozdělených znakem \ před znakem konce řádku (tento kód vložit na začátek skriptu)#3
proměnná != "" {$0 = proměnná; proměnná = "";}
/(^|[^\\])(\\\\)*\\$/ {proměnná = substr($0, 1, length($0) - 1); next;}

6. Parametry příkazů

gawk parametry-gawk [[--] vstupní-soubory]
gawk parametry-gawk [[--] parametry-skriptu]
gawk parametry-kromě-e-f-i program [[--] vstupní-soubory]
gawk --version
-F hodnotaPřednastaví hodnotu proměnné FS (vstupního oddělovače sloupců).
-v proměnná=hodnotaPřednastaví hodnotu určité proměnné.
-f souborNačte kód ke spuštění z daného souboru.
-e kódVezme uvedený kód ke spuštění.
-bVstup a výstup realizuje po bajtech, ne v UTF-8.
--dump-variables=souborPo skončení zapsat hodnoty všech proměnných do daného souboru.
--profile=souborShromáždí „profilovací“ data a po skončení programu je zapíše do uvedeného souboru. (Nezkoušeno.)
--sandboxVypne všechny funkce, které by mohl skript použít k přístupu k jiným souborům než těm, které mu byly předány na příkazovém řádku; to zahrnuje např. funkci „system()“, přesměrování výstupů apod.

Poznámka: Parametry -f a -e můžete kombinovat a zadávat opakovaně. Každý další takový parametr přidá takový kód k již načtenému, takže se nakonec všechny spojí do jednoho programu.

7. Instalace na Ubuntu

sudo apt-get install gawk

8. Tipy a zkušenosti

  • V AWK jsou všechna pole asociativní (včetně těch indexovaných celými čísly), a tedy neuspořádaná. Při indexování pole číslem se číslo nejprve převede na řetězec.
  • Je velmi často využívána syntaktická zkratka, že literál regulárního výrazu (např. /^a/) se automaticky rozšíří na test načteného řádku (např. „($0 ~ /^a/)“).
  • V AWK je středník potřeba jen k oddělení příkazů na jednom řádku, přesto z důvodu přehlednosti doporučuji ho psát na konci příkazu s výjimkou případu, kdy jde o jediný příkaz v bloku, k němuž těsně přiléhají složené závorky, např. „{print $0}“.
  • Skalární proměnné se do funkcí předávají hodnotou, pole odkazem.
  • Hodnoty ARGC a ARGV je možno za běhu skriptu bez omezení měnit, a tím ovlivňovat, které další soubory gawk či mawk otevře. Na již otevřené soubory to ale nemá vliv.
  • Používání koprocesů vyžaduje pečlivou synchronizaci mezi procesy. Existují dvě situace, které vedou k zamrznutí programu a musíte se jim vyhnout: 1) Pokus o přečtení řádku z výstupu koprocesu, zatímco koproces nezapisuje, ale sám čeká na další vstup. 2) Zapsání velkého množství dat (cca od desítek kilobajtů) na vstup koprocesu, která koproces nenačte. (V takovém případě se naplní buffer roury.)
  • V literálech regulárních výrazů je nutno odzvláštňovat obyčejná lomítka, a to dokonce i uvnitř hranatých závorek, např. „a*[x\/y]+“, v dynamických regulárních výrazech je není nutno odzvláštňovat.
  • Chcete-li příkaz pokračovat na další řádce, vložte před konec řádky „\“.
  • Obsahuje-li skript pouze vzorky BEGIN a žádné jiné, AWK nebude otevírat vstupní soubory a po vykonání průchodu BEGIN okamžitě skončí. Toho lze využít k napsání programu, který vstup nezpracovává.
  • Nestojí-li za sekvencí zpětných lomítek v řetězci náhrady funkcí sub() a gsub() „&“, chová se toto odzvláštňování nelogicky – méně než tři zpětná lomítka se použijí tak, jak jsou, a každá čtveřice zpětných lomítek se zredukuje na dvě zpětná lomítka a zbytek sekvence se bere jako od začátku, takže např. 6 zpětných lomítek (v řetězci zapsaných jako 12) zapíše při náhradě čtyři zpětná lomítka, protože první čtyři lomítka se zredukovala na dvě a zbylá dvě se vzala tak, jak jsou. Toto neplatí ve funkci gensub(), ta se chová konzistentně a každou dvojici zpětných lomítek zredukuje na jedno, ať za ní následuje ampresand nebo ne. Pokud tedy potřebujete nahrazovat shody regulárního výrazu zpětnými lomítky, doporučuji vždy řetězec náhrady předem otestovat a pamatovat, že funkce sub() a gsub() zachází se zpětnými lomítky, za kterými nenásleduje ampresand, jinak než funkce gensub().
  • Soubory s konci řádek CR-LF (typicky z Windows) lze snadno zpracovat při nastavení „RS="\r\n"“; analogicky soubory s řádky ukončenými LF lze zpracovat s nastavením „RS="\r"“.
  • GNU awk plně podporuje znaky UTF-8 cca do hodnoty 50000. Od určité hodnoty dál s nimi pracuje chybně, takže není vhodný např. ke zpracování emoji-znaků.

9. Další zdroje informací

10. Pomocné funkce a skripty

@lkk retence – načte celý standardní vstup do paměti a po uzavření vstupu jej vypíše na výstup#1
#!/bin/bash
exec gawk -b -e 'BEGIN {RS = FS = "^$"; ORS = "";} {print}'

11. Zákulisí kapitoly

V této verzi kapitoly chybí:

  • nic

Tato kapitola záměrně nepokrývá:

  • nic
1 Pozor: zvláštní průchod END se vykoná i tehdy, je-li skript ukončován příkazem „exit“!
2 Pozor: zvláštní průchod ENDFILE se nevykoná, pokud je zpracování souboru předčasně ukončeno, např. příkazem „nextfile“ či „exit“.
3 Tato funkce je nejužitečnější u parametrů funkcí; díky ní může funkce ověřit, že jí v určitém parametru bylo předáno pole, nebo naopak skalární hodnota.
4 Při řazení uživatelskou funkcí musíte zadat funkci, která přijme parametry „klíč-L“, „hodnota-L“, „klíč-R“ a „hodnota-R“ v tomto pořadí a vrátí záporné číslo, je-li L-strana menší než R-strana; kladné číslo, je-li větší; a nulu, jsou-li si obě strany rovny.
5 Poznámka: cyklus přiřazuje proměnné hodnoty INDEXŮ daného pole v LIBOVOLNÉM pořadí! Pro přístup k hodnotám v poli je musíte indexovat.
6 Přepínač switch pracuje v gawk stejně jako v jazyce C, ovšem pracuje s řetězci místo celých čísel.
7 Poznámka: tento příkaz přeskočí odpovídající průchod ENDFILE!
8 Je-li uvedena hodnota „kolik-přeskočit“, před načtením sloupce se přeskočí daný počet znaků. Výhradně u posledního sloupce můžete místo počtu znaků zadat „*“; v takovém případě se do daného sloupce uloží všechny zbylé znaky.
9 Do obou uvedených proměnných můžete také přiřadit novou hodnotu, a změnit tak číslování řádku pro zbytek souboru (resp. veškerého vstupu)
10 Nelze použít v blocích BEGIN a END.
11 Počet sloupců lze i nastavit.
12 Výchozí hodnota je „ “ (mezera); může být přednastaven také parametrem příkazové řádky „-F“.
13 Výchozí hodnotou je konec řádku „\n“.
14 Poznámka: vrací-li 0, stejně má být čten standardní vstup.
15 Znak # není interpretován jako začátek komentáře uvnitř řetězců ani literálů regulárních výrazů.
16 Příkaz print zapíše na výstup svoje parametry, oddělené obsahem proměnné „OFS“ (výchozí hodnotou je " "), a za poslední parametr přidá navíc hodnotu proměnné „ORS“ (výchozí hodnota je "\n").
17 Funkce printf() funguje stejně jako v jazyce C, až na to, že parametr %c dokáže vypisovat UTF-8 znaky v rozsahu 0 až cca 55000 (ale např. místo znaku č. 55339 vypíše „+“).
18 Tato varianta funkce „close()“ vrací 0 v případě úspěchu, jiná hodnota značí chybu.
19 Funkce „close()“ počká na skončení příkazu a vrátí jeho návratovou hodnotu.
20 Odkazovaný příkaz se spustí v interpretu /bin/sh a svoje vstupy a výstupy zdědí od instance GNU awk, kterou byl spuštěn, pokud je výslovně nepřesměrujete.
21 Poznámka: po použití této konstrukce pravděpodobně budete muset obnovit hodnoty proměnných RS, $0, RT, NR a FNR.
22 Po uzavření vstupu koprocesu můžete pouze číst z jeho výstupu. Pokus o další zápis před úplným ukončením koprocesu je fatální chyba.
23 Funkce close() v tomto případě vrátí návratovou hodnotu koprocesu vynásobenou 256.
24 Nebyla-li shoda s regulárním výrazem nalezena, funkce match() vrací 0; jinak nastaví proměnné RSTART a RLENGTH na pozici a délku nalezeného podřetězce a vrátí hodnotu RSTART. Vždy vybírá nejlevější a nejdelší shodu.
25 Funkce „patsplit()“ vyhledá všechny shody řetězce s regulárním výrazem a vrátí jejich počet (N). Předané pole pak smaže a naplní těmito shodami. Zadáte-li i pole pro oddělovače, pak ho tato funkce vyplní podřetězci, které zbyly mezi jednotlivými shodami, přičemž řetězec před první shodou bude umístěn na indexu 0 a řetězec za poslední shodou na indexu N.
26 Vrátí 0, nebyl-li podřetězec nalezen; jinak vrátí pozici podřetězce (číslovanou od 1).
27 V gawk tyto funkce rozpoznávají znaky národní abecedy (pravděpodobně podle „locale“), v mawk účinkují pouze na ASCII znaky.
28 Vhodné jen pro maxima do 16 777 215. Pro vyšší maximum bude množina vrácených hodnot pravidelně přerušovaná, což pro některé druhy využití nemusí vadit. Správným řešením je bitová kombinace více volání funkce „rand()“.
29 Bez parametru „1“ vypíše lokální čas, s ním vypíše UTC. Pro „formát“ – viz kapitolu „Datum, čas a kalendář“.
30 Direktiva „@namespace“ musí být použita na úrovni souboru (tj. mimo jakýkoliv blok) a platí do nejbližší další direktivy @namespace nebo do konce souboru. Účinkuje pouze v souboru, ve kterém je uvedena. Je-li vložen nebo připojen kód z jiného souboru (např. direktivou „@include“), ten má svoje vlastní řízení jmenného prostoru a začíná vždy globálním jmenným prostorem „awk“.
31 Aktuální jmenný prostor nemá vliv na interpretaci identifkátorů ve vkládaném souboru! Na jeho počátku bude platit jmenný prostor „awk“, dokud nebude změněn direktivou „@namespace“.
[BY-SA]

Veškerý obsah této stránky (text, obrázky, zdrojový kód) je možno upravovat a šířit pod podmínkami licence Creative Commons Attribution-ShareAlike 4.0 International. Upozorňuji, že uvedená licence vyžaduje uvedení seznamu autorů, licence a zdroje a poskytnutí stejné či kompatibilní licence k provedeným změnám, jsou-li nějaké. Příslušné údaje jsou dostupné na stránce „Přehled autorů“. Šíření obsahu bez těchto údajů nebo šíření upravené verze bez poskytnutí adekvátní licence k provedeným úpravám je pravděpodobně porušení licenčních podmínek a může být postihováno. Poskytování zdrojového kódu při šíření není touto licencí vyžadováno.

Pro nové verze, další informace, aktuální zdrojový kód a možnost se zapojit do projektu „Linux: Kniha kouzel“ navštivte jeho repozitář na GitHubu.