AWK – Wprowadzenie
AWK to interpretowany język programowania, którego głównym celem jest wyszukiwanie oraz przetwarzanie wzorców w plikach lub strumieniach danych. Program ten został pierwotnie stworzony dla systemów operacyjnych opartych na UNIX-ie, a obecnie dostępny jest również na innych platformach.
Język AWK w dużym stopniu opiera się na tablicach asocjacyjnych, stringach oraz wyrażeniach regularnych. Nazwa języka pochodzi od początkowych liter nazwisk jego twórców: Alfreda V. Aho, Petera Weinbergera oraz Briana Kernighana. Często zapisywana jest małymi literami jako awk, wymawiana jak pierwsza sylaba w słowie awkward.
Definicja języka AWK znajduje się w standardzie POSIX 1003.2 Command Language And Utilities. Ta wersja opiera się na opisie zawartym w książce The AWK Programming Language autorstwa Aho, Weinbergera i Kernighana, z dodatkowymi właściwościami w wersji awk z SVR4.
W wierszu poleceń można podać opcje dla awk, tekst programu (jeśli nie został podany za pomocą opcji -f lub –file) oraz wartości, które mają być dostępne w predefiniowanych zmiennych ARGC i ARGV.
Struktura programów AWK
„AWK jest językiem przeznaczonym do przetwarzania plików tekstowych. Plik jest traktowany jako zbiór rekordów, przy czym domyślnie każdy wiersz stanowi osobny rekord. Każda linia jest dzielona na pola, co pozwala traktować pierwsze pole jako pierwsze słowo, drugie pole jako drugie słowo itd. Program AWK składa się z sekwencji instrukcji w formacie wzorzec-akcja. AWK przetwarza dane linia po linii. Każda linia jest analizowana w poszukiwaniu wzorców, a dla każdego dopasowanego wzorca wykonywana jest przypisana do niego akcja.” – Alfred V. Aho
Program AWK składa się z sekwencji instrukcji w formacie wzorzec-akcja oraz opcjonalnych definicji funkcji.
wzorzec { instrukcje akcji }
function nazwa(lista parametrów) { instrukcje }
gdzie wzorzec to zazwyczaj jakieś wyrażenie, a akcja to lista komend. Wejście jest dzielone na rekordy, które domyślnie oddzielane są znakiem nowej linii.
Dla każdego rekordu wejścia awk dokonuje porównania, sprawdzając, czy odpowiada on któremuś wzorcowi w programie. Jeśli wzorzec pasuje do rekordu, zostaje wykonana przypisana do niego akcja. Wzorce są sprawdzane w kolejności ich występowania. Domyślną akcją jest wypisanie rekordu.
Komendy i składnia
Komendy AWK składają się z wywołań funkcji, przypisania wartości do zmiennych, obliczeń lub ich kombinacji. AWK oferuje wbudowane wsparcie dla wielu funkcji. Niektóre wersje pozwalają na dynamiczne linkowanie bibliotek, co umożliwia korzystanie z jeszcze większej liczby funkcji.
Dla uproszczenia nawiasy klamrowe ({}) w poniższych przykładach zostaną pominięte.
Polecenie print jest używane do wyświetlania tekstu. Wyjście zawsze kończy się predefiniowanym separatorem rekordów (output record separator – ORS), który domyślnie jest znakiem nowej linii. Najprostsze użycie polecenia print to:
Wyświetla zawartość bieżącego rekordu.
W AWK rekordy dzielone są na pola, które można wyświetlać osobno:
print $1
Wyświetla pierwsze pole bieżącego rekordu.
print $1, $3
Wyświetla pierwsze i trzecie pole bieżącego rekordu, oddzielając je separatorem pola (output field separator – OFS), domyślnie spacją.
Mimo że zapis pól ($X) może przypominać zapis zmiennych (jak w Perlu), to odnosi się do pól bieżącego rekordu. Ponadto $0 odnosi się do całego rekordu, więc polecenia „print” oraz „print $0” działają identycznie.
Polecenie print pozwala również na wyświetlenie wyników obliczeń lub wywołań funkcji. Na przykład:
print 3+2
print foobar(3)
print foobar(zmienna)
print sin(3-2)
Można także przekierować wyjście do pliku:
print „wyrażenie” > „nazwa pliku”
lub do innego polecenia za pomocą potoku:
print „wyrażenie” | „polecenie”
Zmienne i tablice
Zmienne
Zmienne w AWK są dynamiczne – powstają w momencie, gdy są po raz pierwszy użyte. Nazwy zmiennych mogą zawierać znaki w zakresie [A-Za-z0-9_], ale nie mogą być słowami kluczowymi. Zmienne oraz pola mogą być liczbami (zmiennoprzecinkowymi), łańcuchami lub jednym i drugim jednocześnie. Interpretacja wartości zmiennej zależy od kontekstu. W wyrażeniu numerycznym jest traktowana jako liczba, natomiast w wyrażeniu łańcuchowym – jako łańcuch.
AWK obsługuje tablice jednowymiarowe, a także umożliwia symulowanie tablic wielowymiarowych. W trakcie działania programu ustawiane są różne predefiniowane zmienne, które są opisane poniżej.
Zmienne wbudowane
Zmienne wbudowane w AWK obejmują m.in. zmienne określające pola: $1, $2 itd. Zwracają one wartość lub tekst przechowywany aktualnie w danym polu rekordu. Oprócz tego AWK ma także inne zmienne:
Tablice
Tablice są indeksowane wyrażeniem ujętym w nawiasy kwadratowe ([]). Jeśli wyrażenie jest listą wyrażeń (wyrażenie, wyrażenie, …), indeks tablicy jest tworzony przez połączenie wartości (łańcuchowych) każdego wyrażenia, oddzielonych wartością zmiennej SUBSEP. Dzieje się tak, ponieważ AWK obsługuje wyłącznie tablice asocjacyjne, gdzie klucze numeryczne są zapisane jako łańcuchy.
Symulowanie tablic wielowymiarowych polega na łączeniu poszczególnych indeksów w unikalny łańcuch. Na przykład:
przypisuje łańcuch „hello, world\n” elementowi tablicy x, o indeksie będącym łańcuchem „A\034B\034C”.
Jeśli tablica ma wielokrotne indeksy, można użyć konstrukcji (i, j) in array. Element można usunąć z tablicy za pomocą polecenia delete. Polecenie delete można także zastosować do usunięcia całej zawartości tablicy, podając jej nazwę bez indeksu.
Funkcje
Funkcje są wykonywane po ich wywołaniu w wyrażeniach występujących we wzorcach lub akcjach. Definicja funkcji składa się ze słowa kluczowego function, jej nazwy, argumentów oraz ciała. Oto przykład funkcji:
Tę funkcję można wywołać w następujący sposób:
Między nazwą funkcji a nawiasem otwierającym można wstawić spację jedynie podczas deklaracji – w wywołaniu nawias musi znajdować się bezpośrednio po nazwie funkcji. Ma to na celu uniknięcie niejednoznaczności składni z operatorem konkatenacji. Ograniczenie to nie dotyczy funkcji wbudowanych.
Funkcje mogą mieć zmienne lokalne. Ich nazwy dodawane są na końcu listy argumentów w definicji funkcji. Zazwyczaj przed deklaracją zmiennych lokalnych dodaje się kilka białych znaków, aby wskazać, gdzie kończą się argumenty funkcji i zaczynają zmienne lokalne.
Zamiast słowa function można używać słowa funct.
Operatory
Operatory w AWK, w kolejności malejącego priorytetu, to:
Wywołanie programu AWK
Tekst programu jest interpretowany tak, jakby wszystkie pliki programu zostały połączone w jedną całość, przy czym priorytet mają pliki podane jako argumenty polecenia. Umożliwia to budowanie bibliotek funkcji AWK bez konieczności włączania ich do każdego nowego programu, który z nich korzysta. Pozwala to również na łączenie funkcji bibliotecznych z programami uruchamianymi z wiersza poleceń. Zmienna środowiskowa AWKPATH określa ścieżkę przeszukiwania, używaną do znajdowania plików źródłowych podanych w opcji -f. Jeśli ta zmienna nie istnieje, domyślną ścieżką staje się .:/usr/local/share/awk. (Faktyczny katalog może się różnić, w zależności od tego, jak skompilowano i zainstalowano awk). Jeśli nazwa pliku podana w opcji -f zawiera znak /, przeszukiwanie ścieżki nie jest wykonywane.
Program AWK jest wykonywany w następującej kolejności:
- inicjalizacja zmiennych podanych w opcjach -v,
- kompilacja do formy wewnętrznej,
- wywołanie kodu zawartego w blokach BEGIN (o ile istnieją),
- odczytywanie plików określonych w tablicy ARGV,
- odczytywanie standardowego wejścia, jeśli pliki nie zostały podane.
Z poziomu wiersza poleceń można również ustawić wartość zmiennej, podając zamiast nazwy pliku ciąg zmienna=wartość. Taki sposób inicjalizacji zmiennych przydaje się do dynamicznego przypisywania wartości zmiennym, które AWK wykorzystuje do określenia, jak dane wejściowe są dzielone na pola i rekordy. Jest to również użyteczne do kontroli stanu, gdy zachodzi potrzeba wielokrotnego czytania tego samego pliku. Jeżeli wartość konkretnego elementu ARGV jest pusta („”), awk ją pomija.
Przykłady zastosowań
Hello World
Poniżej znajduje się przykład programu „Hello world” napisanego w AWK:
Nie ma konieczności dodawania na końcu polecenia exit. Jedynym wzorcem jest BEGIN, więc żadne argumenty z linii komend nie są przetwarzane.
W niektórych wersjach AWK oraz w niektórych krajach dodanie znaku „_” przed łańcuchem znaków spowoduje, że zostanie on wypisany w języku narodowym. Na przykład we Francji może to być „bonjour, monde!”.
Wypisywanie linii zawierających więcej niż 80 znaków
Zliczanie liczby słów
Program zlicza liczbę słów na wejściu i wypisuje liczbę słów, linii oraz znaków wprowadzonych danych (podobnie jak polecenie wc).
Ze względu na brak wzorca w pierwszej linii programu, akcja jest wykonywana dla każdego wiersza wejścia.
Suma numerów ostatnich słów
Wartość zmiennej s jest zwiększana o numer ostatniego słowa z każdego rekordu.
Na końcu wejścia wzorzec END pasuje, więc zmienna s jest wypisywana. Jeśli wejście nie zawiera żadnej linii, to ponieważ zmiennej s nie przypisano żadnej wartości, będzie to pusty ciąg. Dodanie zera na końcu podczas wypisywania s wymusza traktowanie zmiennej jak liczby. W rezultacie nawet, gdy s jest pustym ciągiem, na wyjściu nie pojawi się pusta linia, lecz 0.
Wypisanie określonej liczby pasujących linii wejścia
$ yes Wikipedia | awk 'NR % 4 == 1, NR % 4 == 3 { printf „%6d %s\n”, NR, $0 }’ | sed 7q
1 Wikipedia
2 Wikipedia
3 Wikipedia
5 Wikipedia
6 Wikipedia
7 Wikipedia
9 Wikipedia
$
W tym przypadku polecenie yes wypisuje słowo „Wikipedia” tak długo, aż sed wykryje, że zostało wypisanych 7 linii. Dalsza część polecenia wypisuje każdą z linii z numerem. Wypisywane są tylko linie, których numery dają resztę z dzielenia przez 4 w zakresach od 1 do 3.
Obliczanie częstotliwości występowania słów
Program wykorzystuje tablicę asocjacyjną:
Blok BEGIN ustawia separator pola na dowolny znak, który nie jest literą. Warto zauważyć, że separatory mogą być również wyrażeniami regularnymi.
Następnie następuje akcja wykonywana na każdej linii wejścia: dla każdego pola w linii zwiększana jest liczba razy, jakie to słowo (uprzednio zamienione na małe litery) występowało. Na końcu wypisywane są wszystkie słowa wraz z częstotliwościami ich występowania.
Samodzielne skrypty AWK
Podobnie jak w wielu innych językach, skrypt AWK można napisać, poprzedzając go znakiem „shebang”. Na przykład, komenda hello.awk wypisująca tekst „Hello, world!” może być zapisana w pliku o nazwie hello.awk, mającym następującą zawartość:
Opcja -f informuje awk, że następny argument to nazwa pliku, z którego należy przeczytać program, a jest on tam umieszczany przez powłokę systemową podczas działania, tak jakby wywołano polecenie /usr/bin/awk -f hello.awk.
Przypisy
Zobacz też
- sed
- perl
- polecenia systemu operacyjnego Unix
Linki zewnętrzne
- Strona domowa GNU Awk
- The Amazing Awk Assembler by Henry Spencer.
- gawk(1) – strona podręcznika systemu Linux
- Gawkinet: TCP/IP Internetworking with Gawk