Dvanácté cvičení – AWK – základy
AWK je mocnější příbuzný sed
u, o kterém jsme měli desáté cvičení.
Jak spustit AWK:
awk 'prikazy' [vstupni_soubor1...]
awk -f soubor_s_prikazy [vstupni_soubor1...]
awk -v RS='X' ...
nastaví do AWK zvenku proměnnou RS
na hodnotu X
Tvar pravidla:
VZOR {příkazy}
Vzory jsou podobné, jako v sed
u, ale umí toho víc:
{ print }
– vypíše všechny řádky (vzor je prázdný)/regex/ { print }
– vypíše řádky odpovídající regexu!/regex/ { print }
– vypíše řádky neodpovídající regexuNR==12 { print }
– vypíše jen, pokud proměnná rovna 12 (v tomto případě číslo záznamu/řádku je 12)BEGIN {...}
– příkazy spouštějící se před načtením prvního záznamuEND {...}
– příkazy spouštějící se po posledním záznamu
Speciální proměnné:
Vstup a výstup:RS
(record separator) – oddělovač záznamů (defaultně newline, tedy záznamy jsou řádky)FS
(field separator) – oddělovač polí v záznamu (defaultně mezery)ORS
(output record separator) – oddělovač záznamů ve výstupuOFS
(output field separator) – oddělovač polí ve výstupu
Záznamy a pole v záznamu:
$0
– celý záznam (řádek)$1, $2, ...
– jednotlivá poleNR
(number of record) – číslo aktuálního záznamu (číslováno od jedničky)NF
(number of fields) – počet polí v aktuálním záznamu
Pole
Chovají se jako asociativní pole, není potřeba nijak deklarovat ani alokovat, stačí přiřadit do nějakého políčka:
pole[42] = 42
pole[matfyz] = "MFF UK"
pole[2,7] = $0 # Fungují i vícerozměrná pole
print pole[50] # Jenom odřádkuje, nijak si nestěžuje
Příkazy
Příkazy jsou od sebe odděleny koncem řádky nebo středníkem.
print
(vypíše a odřádkuje)printf
(formátovací řetězec a parametry, nemá na konci automatický newline)next
(načte nový řádek a začne ho zpracovávat od začátku příkazů)- Práce s čísly (sin, cos, sqrt, rand, …) – hledejte v manuálu "Numeric Functions"
- Práce se stringy (length, index, tolower, toupper, …) hledejte v manuálu "String Functions"
- Podmínky – podobně jako v C –
if ($1 > 0) print "ANO"; else print "NE"
- Cykly:
while (x > 0) { ... }
for (i=0; i<5; i++) print i
for (promenna in pole) print promenna
– vrací v nedeterministickém (náhodném) pořadí
Příklady:
- Napište příkaz pro awk, který sečte všechny čísla na vstupu
- Vypište pomocí awk každou desátou řádku vstupu
- Vypište pomocí awk z každé řádky první a poslední slovo
- Napište awk skript/příkaz, který každou druhou řádku vstupu převede na velká písmena
- Napište awk skript/příkaz, který otočí pořadí slov na každé řádce
- Napište v AWK vlastní
wc
počítající počet řádků, počet slov a počet znaků a vypište je na konci. Stáhněte si soubor aircrafts2.csv (data o nehodách letadel), třeba pomocíwget http://kam.mff.cuni.cz/~setnicka/static/aircrafts2.csv
- Spočítejte pomocí awk průměrný počet pasažérů na palubě (sloupec "Aboard")
- Vypište havárie, kde zemřeli všichni na palubě (naformátujte výstup buď pomocí
OFS
neboprintf
) - Spočítejte pomocí awk průměrné procento přeživších lidí na palubě a rozptyl tohoto čísla (rozptyl počítejte jako ${1\over n}\sum(x_i - E(x))^2$, abyste si vyzkoušeli pole)
- Vymyslete awk skript/příkaz, který bude mazat nadbytečné prázdné řádky – tedy každou posloupnost za sebou jdoucích prázdných řádků změní na jediný prázdný řádek. */?>
Řešení 5c
#!/usr/bin/awk -f
BEGIN {FS=";"} # Načítáme csv oddělené středníky
NR>1 {
# Některé řádky obsahují počet pasažérů 0 nebo NA, ty nechceme
if ($7 != "NA" && $7 > 0) {
# Odložíme si čísla do pole, abychom se k nim později dostali z ENDu
pole[NR] = $6/$7
sum += $6/$7
}
}
END{
prumer = sum/NR
# Spočítáme rozptyl pomocí již spočítaného průměru
for (i = 1; i <= NR; i++) rozptyl += (pole[i] - prumer) ** 2
rozptyl /= NR
printf("Prumer je %f, rozptyl je %f\n", prumer, rozptyl)
}
*/?>