Wojciech Complak Wojciech.Complak@cs.put.poznan.pl AWK Plan wykładu wprowadzenie składnia programów wzorce, operatory, zmienne instrukcje tablice funkcje standardowe funkcje użytkownika wejście/wyjście, interfejs do systemu operacyjnego 1.02 AWK (2/38) Wprowadzenie Najprostszy program narzędzie linii poleceń do przetwarzania tekstu nazwa pochodzi od nazwisk autorów: Alfred V. Aho, Peter J. Weinberger i Brian W. Kernighan 1977, AT&T Bell Laboratories, pierwsza wersja 1985, druga wersja rozszerzona i ujednoznaczniona 1986, pierwsza wersja GAWK dostępnych jest wiele darmowych i komercyjnych implementacji interpreterów AWK (zgodnych z 1., 2. wersją języka, standardem Posix, zawierających niestandardowe rozszerzenia itd.) kompilatory i debuggery są zwykle komercyjne AWK (3/38) BEGIN print "Hello world" uruchamianie krótkich programów: [g]awk 'BEGIN print "Hello world" ' uruchamianie dłuższych programów programy tworzymy za pomocą edytora tekstowego (wielkość liter jest istotna) nie ma standardowego rozszerzenia (zwykle.awk) [g]awk -f source-file input-file1 input-file2... AWK (4/38) składnia programów wzorzec akcja wzorzec akcja # komentarz # komentarz... $0 cały wiersz (rekord) FS separator pól (domyślnie FS = " ", ciąg spacji i/lub tabulacji) $1, $2, $NF pola bieżącego wiersza (rekordu) NF liczba pól w bieżącym wierszu (rekordzie) RS separator rekordów (domyślnie RS = "\n") NR numer bieżącego wiersza (rekordu) AWK (5/38) $4 == "RSK" print $2, $1 Nowak Jerzy Malinowski Wojciech AWK (6/38) 1
wzorzec bez instrukcji: $4 == "RSK" # równoważne programy: # $4 == "RSK" print # $4 == "RSK" print $0 instrukcja bez wzorca (wzorzec pasuje do każdej linii): Nowak Jerzy Kowalski Jan Malinowski Wojciech print $2, $1 AWK (7/38) AWK (8/38) Formatowane wyjście Wzorce BEGIN i END # formatowane wyjście printf("%-15s\t%-9s\n", $2, $1) Nowak Kowalski Malinowski Jerzy Jan Wojciech AWK (9/38) # Program podaje nazwiska i imiona studentów BEGIN print "Nazwisko Imie" print "===================================" printf("%-15s\t%-9s\n", $2, $1) END print "-----------------------------------" Nazwisko Imie =================================== Nowak Jerzy Kowalski Jan Malinowski Wojciech ----------------------------------- AWK (10/38) Wzorce z relacjami Wzorce z relacjami 12 11 2 11 dwa 11 $1 > $2 12 11 dwa 11 AWK (11/38) wzorce z wyrażeniami regularnymi: /reg_expr/ expr ~ /reg_expr/ expr!~ /reg_expr/ /n/ $0 ~ /n/ $1 ~ /n/ $1!~ /n/ AWK (12/38) 2
Wzorce, znaki i sekwencje specjalne Operatory dowolny znak (ale nie \n). początek linii (rekordu) ^x koniec linii (rekordu) x$ grupowanie (x y)z klasa znaków [...] dopełnienie klasy [^...] predefiniowane klasy [:alnum:], [:digit:] konkatenacja x*y* alternatywa x y sekwencja ucieczki \ sekwencje specjalne \a\t\n... liczba oktalna \nnn 0 lub 1 wystąpień x? domknięcie zwrotne x* domknięcie dodatnie x+ odwołanie do pola $expr inkrementacja ++x, x++ dekrementacja --x, x-- potęgowanie expr ^ expr logiczna negacja! unarne plus i minus +x, -x binarne operatory arytmetyczne *, /, %, +, - binarne operatory logiczne <,<=,!=, ==, >, >=, &&, przypisania ^=, %=, *=, /=, +=, -=, = AWK (13/38) AWK (14/38) Wzorce, klasy znaków Dopełnienie klasy, alternatywa wzorców, domknięcia /^n$/ /^.$/ /[0123456789]/ jaka jest różnica między tymi programami? /[^0-9]/ /^[0-9]/ /Jan Jerzy/ $0!~ /[a-za-z_][a-za-z_0-9]*/ /[0-9]/ /[[:digit:]]/ /[0-7]+(Q q O o)/ # /[0-7]*[0-7](Q q O o)/ # /[0-7][0-7]*(Q q O o)/ /[0-9]+(D d)?/ # MASM # MASM AWK (15/38) AWK (16/38) Wzorce złożone, zaprzeczenie wzorca Wzorzec zakresu $1 == "Jerzy" $4 == "KSWD" $1 == "Jerzy" && $4 == "KSWD"!/W/ $0!~ /W/ 2 11 test aa bb 13 gg 11 abc dwa 11 /^test/,/dwa/ print NR ":" toupper($0) 2:TEST 3:AA BB 13 4: GG 11 ABC 5: DWA 11 AWK (17/38) AWK (18/38) 3
Zmienne Instrukcja warunkowa if zmienne standardowe (ARGC, ARGV, FILENAME, NF, NR, FS, OFS, RS, ORS, RLENGTH, RSTART ) pola bieżącego wiersza ($0, $1, $2 ) zmienne użytkownika: + nie ma deklaracji zmiennych + zmienne są tworzone dynamicznie + zmienne mogą zmieniać typ + początkowy typ zmiennej wynika z inicjalizacji + zmienne są globalne (przysłanianie w funkcjach!) przykład: TotalNF += NF END print "liczba pól w pliku=", TotalNF AWK (19/38) bez opcjonalnej części else: if(x == 4) print("x jest równe 4") z częścią else: if((x % 2 == 0) && (x!= 0))printf("x jest parzyste") else printf("x jest nieparzyste") składnia: w AWK nie trzeba używać średników jeśli są one ostatnim znakiem w linii (nie dotyczy komentarzy) if((x % 2 == 0) && (x!= 0))printf("x jest parzyste");else printf("x jest nieparzyste") AWK (20/38) Wyrażenie warunkowe?: Pętla while przykład: k = $1 > $2? $1 : $2 print k z pojedynczą instrukcją: i = 0; while(++i <= NF)print i,$i; z blokiem instrukcji: i = 1; while(i <= NF) print i,$i; i++; AWK (21/38) AWK (22/38) Pętla do while Pętla for z pojedynczą instrukcją: i = 1; do print i,$i; while(i++ < NF); z blokiem instrukcji: i = 1; do print i,$i; ++i; while(i < NF); z pojedynczą instrukcją: for(i=1; i<=nf; i++)print i, $i; z blokiem instrukcji: for(i=1; i<=nf; i++) printf("%d ", i); print $i; AWK (23/38) AWK (24/38) 4
Instrukcje break i continue Tablice w pętlach można korzystać z instrukcji break (przerwanie pętli) i continue (przejście do następnej iteracji) pętla while: i=0; while(i<=nf) i++; if(i==6)break; if(i%2==0)continue; print i, $i; pętla for: for(i=1; i<=nf; i++) if(i==6)break; if(i%2==0)continue; print i, $i; tablic nie deklaruje się tablice są dynamiczne i elementy i indeksy mogą być dowolnego typu zbiory indeksów nie są ciągłe wstawianie elementów do tablicy: tab[0] = "Ala" tab[1] = "ma" tab[5] = "kota" tab["kotali"] = "Mruczek" tab["liczbanogkota"] = 3 tab["masakota"] = 3.256 tab[3.1456] = "Pi" AWK (25/38) AWK (26/38) Tablice Tablice przeglądanie indeksów i elementów tablic: for(i in tab)print i, tab[i] uwaga: kolejność przetwarzania indeksów zależy od implementacji gawk 3.0.3: MKS AWK 6.1: 5 kota MasaKota 3.256 LiczbaNogKota 3 KotAli Mruczek 0 Ala 1 ma 3.1456 Pi 3.1456 Pi MasaKota 3.256 LiczbaNogKota 3 KotAli Mruczek 5 kota 1 ma 0 Ala AWK (27/38) testowanie istnienia indeksów w tablicy: if("liczbanogkota" in tab)print "Kot ma nogi if("liczbaogonowkota" in tab)print "Kot ma ogon"; else print "Kot nie ma ogona" usuwanie elementów tablicy: delete tab["masakota"]; funkcja split: t = split("15-07-1410", tab, "-") print t, tab[1], tab[2], tab[3] odpowiedź: 3 15 07 1410 AWK (28/38) Funkcje standardowe Funkcje standardowe funkcje arytmetyczne atan2(x, y) arcus tangens (x/y) w przedziale [-, ) cos(x) cosinus x sin(x) sinus x exp(x) funkcja wykładnicza e x log(x) logarytm naturalny x sqrt(x) pierwiastek kwadratowy x int(x) część całkowita (ucięcie) x srand([x]) inicjowanie ciągu liczb pseudolosowych rand() pseudolosowa liczba z zakresu [0, 1) funkcje łańuchowe (#1/2): sub(r, s [, t]) zastępuje najbardziej lewe najdłuższe wystąpienie podciągu opisanego wzorcem r w łańcuchu t (domyślnie $0) przez s gsub(r, s [, t]) jaksub ale zastępuje wszystkie wystąpienia podciągu opisanego wzorcem r przez s index(s, t) pozycja (w znakach) od której rozpoczyna się łańcuch t w łańcuchu s licząc od 1 (0 jeśli nie odnaleziono t) length([s]) długość łańcucha s, jeśli nie podano argumentu długość $0 AWK (29/38) AWK (30/38) 5
Funkcje standardowe Funkcja standardowe przykład v. 0.9 funkcje łańcuchowe (#2/2): match(s, e) zwraca pozycję, od której w łańcuchu s rozpoczyna się podłańcuch pasujący do wyrażenia regularnego e, ustawia zmienne RSTART i RLENGTH substr(s, m[, n]) zwraca podłańcuch s nie dłuższy niż n rozpoczynający się od pozycji m (licząc od 1), jeśli pominięto n zwraca pozostałą część łańcucha tolower(s), toupper(s) zmienia wielkość liter w łańcuchu sprintf(fmt, expr, expr ) zwraca łańcuch sformatowany zgodnie z formatem funkcji printf zdefiniowanym w fmt gsub(/\ +/," "); print Jerzy Nowak 33089 RSK Jan Kowalski 33780 KSWD Wojciech Malinowski 33990 RSK AWK (31/38) AWK (32/38) Funkcja standardowe przykład v. 1.0 Funkcje użytkownika (#1/4) gsub(/ [[:alnum:]]/," &"); print Jerzy Nowak 33089 RSK Jan Kowalski 33780 KSWD Wojciech Malinowski 33990 RSK wywołania funkcji mogą być zagnieżdżone wywołania funkcji mogą być rekurencyjne instrukcja return może być wykorzystana do powrotu z procedury albo powrotu z funkcji i zwrócenia wartości funkcje mogą być wywoływane w dowolnym miejscu (wywołanie może poprzedzać definicję) liczba argumentów w wywołaniu nie musi być równa liczbie parametrów w definicji, dodatkowe parametry mogą być wykorzystane jako zmienne lokalne (uwaga zmienne są globalne) nie jest przeprowadzana kontrola zgodności typów (skalary/wektory, wartość zwracana przez funkcję) AWK (33/38) AWK (34/38) Funkcje użytkownika (#2/4) parametr Funkcje użytkownika (#3/4) BEGIN for(i=1;i<20;i++) print i, 3, nwp(i,3) function nwp(par_a, par_b) while(par_a!= par_b) if(par_a > par_b)par_a-=par_b; else par_b-=par_a; return par_a; function is_prime(n, i) if(n <= 3)return 1; zmienna lokalna w funkcji if(n % 2 == 0)return 0; for(i = 3;i*i <= n;i += 2) if(n % i == 0)return 0; return 1; zmienna globalna BEGIN for(i=1;i<=30;i++) if(is_prime(i))print i," jest pierwsza" else print i," jest zlozona" AWK (35/38) AWK (36/38) 6
parametr Funkcje użytkownika (#4/4) Wejście/wyjście, interfejs do systemu operacyjnego function is_prime(n) if(n <= 3)return 1; if(n % 2 == 0)return 0; zmienna globalna for(i = 3;i*i <= n;i += 2) if(n % i == 0)return 0; return 1; zmienna globalna BEGIN for(i=1;i<=30;i++) if(is_prime(i))print i," jest pierwsza" else print i," jest zlozona" AWK (37/38) print $1, $2 > "nazwiska_studentow.txt" print $1, $2 >> "nazwiska_studentow.txt" interfejs do systemu operacyjnego system("polecenie") wejście getline [zmienna] < wyrażenie "polecenie" getline [zmienna] zamykanie strumieni (w AWK nie ma uchwytów) close(wyrażenie) AWK (38/38) 7