W tej części:
u gawk
u Programowanie w języku C
u Język C++
u Perl
u Podstawy języków Tcl i Tk
u Inne kompilatory
u Smalltalk/X
u
E:\Moje dokumenty\HELION\Linux Unleashed\Indeks\25.DOC 427
Tim Parker
Rozdzia³ 25. ¨ gawk 427
W tym rozdziale:
u Ogólnie o języku gawk
u Pliki, rekordy i pola
u Kojarzenie wzorców i akcji
u Wywoływanie programów w języku gawk
u Instrukcje strukturalne
Język programowania o nazwie awk został opracowany przez trzech ludzi – byli to: Alfred Aho, Peter Weinberger i Brian Kernighan (nazwa tego języka pochodzi od pierwszych liter ich nazwisk). Program gawk jest implementacją języka awk rozprowadzaną zgodnie z warunkami licencji GNU.
gawk to coś więcej niż zwykły język programowania. Jest on praktycznie niezastąpionym narzędziem dla większości programistów i administratorów systemów. Sam język jest bardzo łatwy do opanowania, a jednocześnie zadziwiająco elastyczny. Gdy poznasz podstawowe zasady programowania w tym języku, będziesz zaskoczony, widząc, w jak wielu różnych sytuacjach może on znaleźć zastosowanie.
Aby pomóc Ci zrozumieć gawk, przedstawimy kolejno jego elementy, popierając teorię przykładami. Oczywiście najlepszym sposobem na zapoznanie się z językiem są samodzielne eksperymenty, do których gorąco zachęcamy. W tym rozdziale przedstawimy tylko podstawowe wiadomości dotyczące języka gawk, żywiąc nadzieję, że rozbudzi to Twoją ciekawość.
gawk został zaprojektowany jako łatwy w użyciu język programowania, który umożliwia pracę z danymi zapisanymi w plikach (obejmuje to również dane przesyłane z innych programów bezpośrednio, za pomocą mechanizmu przekierowania lub mechanizmu potoków, nazywanych po angielsku pipe). Podstawowe możliwości tego języka to:
u wyświetlanie fragmentu lub całej zawartości pliku, poszczególnych kolumn, wierszy czy pól,
u analizowanie tekstów ze względu na występowanie określonych ciągów znaków,
u przygotowanie sformatowanego raportu w oparciu o dane zawarte w pliku,
u filtrowanie tekstów w oparciu o różnorodne systemy filtrów,
u wykonywanie operacji arytmetycznych na danych numerycznych zapisanych w pliku.
Pod wieloma względami język ten idealnie nadaje się na „pierwszy” język programowania, głównie z powodu prostych reguł i wszechstronnego zastosowania w codziennej pracy. Doświadczeni programiści z pewnością również docenią jego prostotę.
Zwykle program napisany w języku gawk pracuje na podstawie o danych zapisanych w pliku. Często są to dane numeryczne, ale gawk radzi sobie również z danymi tekstowymi. Jeśli dane nie są zapisane w pliku, można przesłać je do programu, używając mechanizmu potoków lub innego mechanizmu przekierowania danych. Tylko pliki tekstowe w standardzie ASCII mogą być przetwarzane prawidłowo. Choć gawk umożliwia pracę z plikami binarnymi, rezultaty często okazują się nieprzewidywalne. Ponieważ jednak w systemie Linux większość informacji zapisywana jest w standardzie ASCII, nie stanowi to większego problemu.
Jako prosty przykład pliku, który może być obsłużony przez program napisany w języku gawk, rozpatrzmy plik zawierający książkę telefoniczną. Książka taka składa się z dużej liczby wpisów, ale wszystkie wpisy mają taki sam format: nazwisko, imię, adres, numer telefonu. Cała książka telefoniczna jest posortowana (najczęściej alfabetycznie według nazwisk), ale brak w niej zaawansowanych metod wyszukiwania.
Każdy wiersz takiego pliku jest kompletnym zestawem danych dotyczących jednego numeru telefonicznego i nazywany jest rekordem; przykładowo, rekordem jest wiersz zawierający dane na temat abonenta o nazwisku Jan Kowalski, włączając w to jego adres i numer telefonu.
Każda z informacji zawartych w rekordzie – na przykład imię, nazwisko czy numer telefonu – nazywana jest polem. W języku gawk polem jest każda pojedyncza informacja, natomiast rekordem – zestaw pól odpowiadający opisowi pojedynczej rzeczy. Zestaw rekordów nazywany jest plikiem.
W większości przypadków pola rozdzielane są jednym wybranym znakiem, na przykład spacją, średnikiem, przecinkiem czy znakiem tabulacji. Znak ten nazywany jest separatorem pól. Dobrym przykładem pliku o ściśle określonym formacie rekordów jest plik /etc/passwd, który może wyglądać na przykład tak:
tparker:t36s54hsh:501:101:Tim Parker:/home/tparker:/bin/bashetreijs:2ys639dj3h:502:101:Ed Trejis:/home/etrejis:/bin/tcshychow:1h27sj:503:101:Yvonne Chow:/home/ychow:/bin/bash
Jeśli przyjrzeć się temu plikowi, można zauważyć, że jako separator pól używany jest dwukropek. Każdy z rekordów (wierszy) zawiera siedem pól: identyfikator użytkownika, hasło (zakodowane), numer identyfikacyjny użytkownika, numer identyfikacyjny grupy, pole komentarza, ścieżkę dostępu do katalogu domowego i do domyślnego interpretera poleceń. Dwukropki używane są wyłącznie do rozdzielania poszczególnych pól. Program, który ma wyszukać szóste pole, musi jedynie znaleźć piąty dwukropek (ponieważ przed pierwszym polem nie ma dwukropka) – po nim na pewno nastąpi szóste pole.
Tu napotykamy pierwszy problem. Wróćmy ponownie do przykładu książki telefonicznej. Załóżmy, że zawartość pliku jest następująca:
Smith, John 13 Wilson St. 555-1283Smith, John 2735 Artside Dr, Apt 123 555-2738Smith, John 125 Westmount Cr 555-1728
My wiemy, że każdy z rekordów zawiera cztery pola: nazwisko, imię, adres i numer telefonu. gawk widzi taki plik jednak nieco inaczej. Ponieważ separatorem pól jest spacja, w pierwszym wierszu rozpoznaje on ciąg Smith jako pierwsze pole, ciąg John – jako drugie pole, 13 jako pole trzecie, Wilson – czwarte itd. Z punktu widzenia języka gawk pierwszy wiersz składa się z sześciu pól. Drugi wiersz ma natomiast osiem pól. Dodatkowe znaki białe (spacje i znaki tabulacji) są ignorowane, chyba że zmienisz separator pól na znak spacji lub tabulacji.
Podczas pracy z dowolnym językiem programowania musisz niestety postrzegać dane właśnie w taki sposób, jaki wynika z zasad działania tego języka. Komputery biorą wszystko dosłownie.
Aby można było używać pliku zawierającego książkę telefoniczną zgodnie z naszą koncepcją, najłatwiej jest nieco zmienić jego format, na przykład wstawiając jako separator znak \:
Smith/John/13 Wilson St./555-1283Smith/John/2735 Artside Dr, Apt 123/555-2738Smith/John/125 Westmount Cr/555-1728
gawk domyślnie traktuje znaki białe jako separatory pól, chyba że zostanie poinstruowany, by używać innego znaku. Jeśli pozostaniesz przy ustawieniu domyślnym, to nie ma znaczenia, ile spacji czy tabulatorów będzie występowało obok siebie – zostaną one potraktowane jako pojedynczy separator. Oczywiście istnieje sposób, by zmienić to zachowanie.
W języku gawk istnieje jeden format określony prawie dla wszystkich poleceń. Polecenie składa się z dwóch części: wzorca i odpowiadającej mu akcji. Za każdym razem, gdy uda się dopasować wzorzec do danych wejściowych, wykonywana jest skojarzona z nim akcja.
Podejście to jest nieco podobne do języka naturalnego. Załóżmy, że chcesz wytłumaczyć komuś, jak dojść na pocztę. Mógłbyś na przykład ująć to następująco: „na końcu ulicy skręć w prawo, potem idź aż do znaku stop, skręć w lewo, idź do końca ulicy i skręć w prawo”. Zapis takiej informacji zgodny z filozofią języka gawk mógłby wyglądać tak:
koniec ulicy: skręć w prawoznak "stop": skręć w lewokoniec ulicy: skręć w prawo
Po dopasowaniu wzorca podejmowane są odpowiednie akcje. Nie powinieneś skręcać w prawo, zanim nie dojdziesz do końca ulicy, nie powinieneś skręcać w lewo przed znakiem stop. Przykład jest może nieco uproszczony, ale oddaje ogólną ideę.
W języku gawk pary wzorzec-akcja podaje się w następujący sposób:
/wzorzec1/{akcja1}/wzorzec2/{akcja2}/wzorzec3/{akcja3}
Dzięki takiemu formatowi łatwo zorientować się, gdzie kończy się wzorzec, a zaczyna określenie skojarzonej z nim akcji. Każdy program w języku gawk jest zestawem takich par. Pamiętaj, że wzorce i akcje dotyczą danych tekstowych, więc wzorce są zwykle ciągami znaków, a akcje – poleceniami typu wyświetl czy usuń tekst.
W przypadku, gdy nie został podany żaden wzorzec, każdy tekst uważany jest za „pasujący” i odpowiednia akcja podejmowana jest za każdym razem. Jeśli nie podamy żadnej akcji, gawk skopiuje bez zmian wiersz pasujący do wzorca z wejścia na wyjście.
Spójrzmy na następujący przykład:
gawk '/tparker/' /etc/passwd
Polecenie to spowoduje wyszukanie wszystkich wierszy zawierających tekst tparker w pliku /etc/passwd, i, ponieważ nie określono żadnej akcji, wyświetlenie ich na ekranie. W tym przypadku gawk zachowuje się tak samo jak program grep.
Powyższy przykład pokazuje dwie ważne rzeczy: gawk może zostać uruchomiony z wiersza poleceń (jego parametrami są wtedy pary wzorzec-akcja i nazwa pliku z danymi wejściowymi), a pary wzorzec-akcja należy ująć w pojedynczy cudzysłów, aby mogły zostać odróżnione od nazwy pliku wejściowego.
Język gawk dopasowuje tekst do wzorca litera po literze, więc wzorzec „kot” zostanie odnaleziony zarówno w słowie „kot”, jak i w słowie „maskotka”. Jeśli chcesz wyszukać tylko wiersze zawierające cały wyraz, powinieneś otoczyć wzorzec spacjami (” kot ”). Ważna jest również wielkość liter. Na szczęście w języku gawk dostępnych jest wiele znaków specjalnych rozszerzających lub zawężających zakres poszukiwań; zostaną one omówione w sekcji „Symbole specjalne”.
Wybiegając nieco naprzód, przeanalizujmy następujące polecenie:
gawk '{print $3}' plik2.dat
Spowoduje ono wyświetlenie (akcja określona jest przez polecenie print – wyświetl) trzeciego pola ($3) każdego wiersza pliku plik2.dat (ponieważ nie podano żadnego wzorca). Domyślnym separatorem pól jest spacja, jeśli więc spróbujemy użyć tego polecenia, podając jako plik wejściowy plik /etc/passwd, najpewniej nie zostanie wyświetlony żaden tekst, ponieważ tam separatorem pól jest dwukropek.
Możemy połączyć dwa podane wcześniej przykłady:
gawk '/UNIX/{print $2}' plik2.dat
Powyższe polecenie spowoduje przeszukanie pliku plik2.dat i wyświetlenie drugiego pola każdego wiersza zawierającego wyraz UNIX.
Cudzysłów otaczający parę wzorzec-akcja jest bardzo ważny i nie powinien być pomijany. Bez niego polecenie może nie zostać prawidłowo wykonane. Upewnij się również, że używasz właściwych znaków cudzysłowu (a nie na przykład pojedynczego cudzysłowu na początku, a podwójnego na końcu).
W obrębie jednego polecenia można oczywiście zdefiniować więcej par wzorzec-akcja, np.:
gawk '/skandal/{print $1} /rozwod/{print $2}' plotki.txt
Powyższe polecenie spowoduje wyszukanie w pliku plotki.txt wszystkich wierszy zawierających słowo skandal i wyświetlenie ich pierwszego pola, a następnie ponowne przeszukanie tego pliku od początku, tym razem wyświetlając drugie pole wierszy zawierających słowo rozwod. Przeszukiwanie dla każdej pary wzorzec-akcja rozpoczyna się od początku pliku.
Jak już się pewno zorientowałeś, gawk numeruje poszczególne pola rekordu: pierwsze pole to $1, drugie – $2 itd. Cały rekord nazywa się $0. Dla uproszczenia gawk pozwala opuścić argument $0 w nieskomplikowanych instrukcjach, tak więc wszystkie poniższe polecenia dadzą ten sam rezultat:
gawk '/tparker/{print $0}' /etc/passwdgawk '/tparker/{print}' /etc/passwdgawk '/tparker/' /etc/passwd
Oczywiście gawk potrafi o wiele więcej niż tylko wyszukać i wydrukować fragment tekstu. Można na przykład porównać zawartość danego pola ze stałą:
...
Wolf-1