Linki i moje projekty

Programowanie w AWK

Tytułem wstępu zaznaczę że GAWK jest wersją interpretatora języka skryptowego AWK, opracowywaną w ramach projektu GNU, posiadającym własne rozszerzenia (zwane rozszerzeniami GNU). Z faktu iż jest to język skryptowy wynika iż program wykonywany jest tożsamy z kodem źródłowym - nie ma etapu kompilacji.

Składnia języka jest dość podobna do C, oczywiście nie znajdziemy tu zdecydowanej większości funkcji z biblioteki standardowej C oraz są też bardzo istotne różnice w samej budowie programu. Podstawową z tych różnic jest to iż program w języku AWK składa się z bloków "warunek { instrukcje }" oraz (opcjonalnie) definicji funkcji "function nazwa (argumenty) { instrukcje }". Taka budowa składni wynika z głównego zastosowania do jakiego został stworzony AWK - przetwarzania tekstu.

Skrypty AWK mogą być zapisywane go pliku - wywołujemy przez gawk -f sciezka_pliku, mogą też być podawane w linii poleceń: gawk 'tresc programu' (dla bezpieczeństwa treść tak podawanego programu należy ujmować w '' - inaczej powłoka może z nią zrobić coś niedobrego interpretując zawarte tam znaki specjalne ... . Możemy też w pliku z poleceniami AWK dodać jako pierwszą linię #!/usr/bin/gawk -f oraz dodać mu argument wykonywalności - będzie zachowywał się jak zwykły program przyjmujący dane z stdin lub plików podanych jako argumenty.

Tym razem zaczniemy tradycyjnie ... od "Witaj Świecie" (zakładam że plik w którym umieszczane są przykładowe programy nazywa się "hello.awk" i ma atrybut wykonywalności):

#!/usr/bin/gawk -f

{ printf "Hello World !!!\n" }

XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from heloworld.awk

Wykonanie ./hello.awk spowoduje oczekiwanie na dane wejściowe z sdtin ... po wpisaniu każdej kolejnej linii program wypisze "Hello World !!!" (aby zkończyć Ctrl+D) ... natomiast ./hello.awk jakis_plik wypisze ileś razy ten napis i zakończy działanie ... ale chyba nie o to chodziło. Spróbujmy wiec tak:

#!/usr/bin/gawk -f

BEGIN { printf "Hello World !!!\n" }

XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from heloworld2.awk

Teraz ./hello.awk działa jak byśmy oczekiwali (identycznie też ./hello.awk jakis_plik) - wypisuje "Hello World !!!" i kończy.

Powyższe przykłady obrazują (chyba) podstawową własność języka AWK to co jest zawarte w klamrach wykonywane jest dla każdej pasującej linii (przed klamrami może stać warunek w stylu FNR == 1, co oznacza numer_rekordu == 1 bądź wyrażenie regularne np. ^T[ye] co oznacza że linia zaczyna się od T po którym jest y lub e) oraz są specjalne identyfikatory - poznany BEGIN i END wykonywane odpowiednio na początku i końcu programu. Widzimy też funkcję printf - bliźniaczo podobną do tej z C (powyżej pominąłem nawiasy ale jest to to samo co printf("Hello World !!!\n")).

Widzimy tez że nie ma średników, gdy instrukcja kończy się z końcem linii (ale nic nie stoi na przeszkodzie aby je stawiać), są natomiast konieczne gdy w jednej linii mamy kilka instrukcji.

Kolejnym ważnym aspektem są zmienne i tablice. Nie ma potrzeby określania typu zmiennej, wszystkie zmienne poza zmiennymi wewnętrznymi funkcji są globalne. AWK używa tablic asocjacyjnych - indeksem w tablicy może być cokolwiek (liczba lub napis), nie ma potrzeby ustalania długości tablicy ani typu elementów w niej przechowywanych; poniżej przykład ilustrujący tablice w AWK. Wszystkie te cechy ilustruje poniższy przykładowy kod

#!/usr/bin/gawk -f

function moja_funkcja( zmienna1 ) {
        zmienna2 = sin (2);
        zmienna1 = sprintf("%s @ %f", zmienna1, zmienna2)
        return zmienna1;
}

BEGIN {
        tablica["Hello"]="World";
        tablica["Witaj"]="Świecie";
        for (INDEX in tablica)
                printf("%s %s !!!\n", INDEX, tablica[INDEX])
}

FNR == 1 {
        zmienna3 = "Ala ma kota"
        moja_funkcja(zmienna3);
        # to jest komentarz
        # uwaga: miedzy nazwą funkcja a otwierającym nawiasem nie może być białych znaków
        printf("%s %s\n", zmienna3, zmienna1)
}
FNR == 2 {
        zmienna4 = 5
        zmienna4 = moja_funkcja(zmienna4);
        printf("%s %s\n", zmienna3, zmienna4)
}

XHTML generated by highlight 2.4.5 (http://www.andre-simon.de/) from zmienne_funkcje_i_tablice.awk

Warto zaznaczyć że dość często wykorzystuje się tablice w których interesuje nas tylko index - jest tak dlatego że gwarantuje to unikalność (nie może być dwóch takich samych indeksów), zatem gdy zbieramy napisy i chcemy wyeliminować powtórzenia przyjemnym rozwiązaniem jest nasza_tablica[napis]=0. Oczywiście mogą być też tablice dwu lub więcej wymiarowe: nasza_tablica[indeks1,index2]=wartosc. Na koniec warto zaznaczyć że oprócz powyższego wywołania for mamy też zupełnie standardowe pętle for, while znane z C.

Więcej (w szczególności jak budować wyrażenia regularne oraz wykaz predefiniowanych funkcji) - patrz man 1 gawk oraz:

Skrypty AWK'owe często wykorzystywane są w skryptach powłoki (bash, ...), nie stoi też nic na przeszkodzie aby wykorzystywać je w C - np. przez system() lub exec(); . Warto tutaj zwrócić uwage na przekazywanie zmiennych bashowych do awk - mozna to zrobić (w przypadku prostych skryptów poprzez umieszczenie skryptu w podwójnych cudzysłowiach i zabezpieczniu tych znaków specjalnych których bash nie powinien dotykać poprze \ - np. awk "(\$1==$bash) {print \$0}" (zmienną bashową którą przekazujemy awk jest $bash) albo poprzez przekazanie zmiennej opcją -v - np. awk -v temp=$temp '($1==temp) {print $0}'.

Linki i moje projekty

Zamieszczam tutaj krótki skrypcik który usuwa zadany katalog ze zmiennej systemowej PATH - PATH=`echo $PATH | awk 'BEGIN {RS=":"; FS="\n"} $1!="/sciezka/katalogu/do/usuniecia" {printf("%s:",$1)}'`, a także przykłady skryptów bashowych wykorzystujących AWK:

  • beos_mail2mbox.sh - konwersja skrzynki pocztowej z BeOSa do standardowego mbox'u
  • net_stat.sh - statystyki transferu na zadanym interfejsie sieciowym
  • smtp.sh - prosty serwer SMTP (wykorzystujący do nasłuchu netcat'a), umożliwia sterowanie (wykonywanie zdalnych poleceń przy pomocy odpowiednio spreparowanych maili (jest wymagającym w teorii tylko busybox'a zastępnikiem jakiegoś serwera, pocztowego który otrzymane maile przekazuje do skryptu wyciągającego z nich potrzebne dane przy pomocy grep/cut/awk)
  • engine.sh - dość rozbudowany skrypt bash'owo-awk'owy obsługującego moją stronę www

Copyright (c) 1999-2008, Robert Paciorek (http://www.opcode.eu.org/), BSD-type license


Redystrybucja wersji źródłowych i wynikowych, po lub bez dokonywania modyfikacji JEST DOZWOLONA, pod warunkiem zachowania niniejszej informacji o prawach autorskich. Autor NIE ponosi JAKIEJKOLWIEK odpowiedzialności za skutki użytkowania tego dokumentu/programu oraz za wykorzystanie zawartych tu informacji.

This program is free software. Redistribution and use in source and binary forms, with or without modification, ARE PERMITTED provided save this copyright notice. This document/program is distributed WITHOUT any warranty, use at YOUR own risk.

Valid XHTML 1.1 Dokument ten (URL: http://www.opcode.eu.org/awk) należy do serwisu OpCode. Autorem tej strony jest Robert Paciorek, wszelkie uwagi proszę kierować na adres e-mail serwisu: webmaster@opcode.eu.org.
Data ostatniej modyfikacji artykulu: 2008-05-28 01:35:32 (UTC) (data ta może być zafałszowana niemerytorycznymi modyfikacjami artykułu).