Your SlideShare is downloading. ×
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Awk
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Awk

254

Published on

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
254
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 10 GUST, Zeszyt 7 1996 AWK jest językiem strukturalnym, a więc jego Narzędzia programy są czytelne i przejrzyste. Pod tym ˆ względem AWK przypomina język Pascal. Cechą charakteryzującą programy AWK-owe AWK – opis języka z przykładami jest ich zadziwiająca krótkość w stosunku do ilości wykonywanych zadań. Często zdarza się, że nasz Bogusław Lichoński program ma zaledwie 2–3 linijki, wykonanie jego i Tomasz Przechlewski trwa kilka sekund, a wykonuje on zadanie, które ręcznie wykonywane może być kilka godzin. Co to jest AWK? AWK i TEX Istnieją osoby, których nie trzeba przedstawiać Plik źródłowy TEX-a jest plikiem tekstowym o okre- żadnemu informatykowi. Knuth, Kernighan, Aho, ślonej strukturze. Na przykład do wykonania Wirth i inni znani są nam wszystkim chociaż ze zamian globalnych w naszym źródle wystarczy słyszenia. Dlatego wydaje nam się, że nie trzeba zwykły edytor tekstowy, co jednak zrobić jeżeli reklamować języka programowania utworzonego zamian zamierzamy dokonywać na wielu plikach przez panów Alfreda Aho, Petera Weinbergera i dokonujemy ich codziennie. Jeżeli nasz edytor i Briana Kernighana. nawet zapamiętuje kilka ostatnich zamian, to i tak AWK – bo o nim mowa – powstał już w 1977 jest to lista skończona! roku i naszym zdaniem nie jest wcale językiem Wykonywanie w kółko tych samych czynności archaicznym. Wręcz przeciwnie! Jeśli przyjmiemy, jest nie tylko nużące, powoduje więcej błędów że ma służyć do konkretnych celów, to za chwilę i pozbawia nas radości z napisania krótkiego okaże się, że może być narzędziem wprost nie- programiku w AWK-u, dając w zamian niesmak, zastąpionym w codziennej pracy z plikami tek- zmęczenie, brak poczucia własnej wartości. stowymi. W szczególności idealnie nadaje się do współpracy z TEX-em. Podstawy AWK-a System UNIX wyposażony jest w szereg narzę- Każdy program języka AWK składa się z dowolnej dzi wspomagających pracę użytkowników. AWK ilości par stał się jednym ze standardowych narzędzi tego wzorzec { akcja } systemu, choć implementacje AWK-a znaleźć można niemal na każdej platformie systemowej. Wzorzec jest wyrażeniem logicznym, które może W jednym zdaniu można powiedzieć, że AWK być prawdziwe (wówczas wykonywana jest akcja ) służy do transformacji szeroko pojętych danych lub fałszywe ( akcja nie jest wykonywana). tekstowych. Istotą działania AWK-a jest przetwa- No tak – zapyta czytelnik – ale do czego rzanie pliku lub plików wejściowych według za- ten wzorzec ma pasować? Odpowiedź na to danego zbioru reguł, generując pewien strumień pytanie wyjaśnia istotę działania języka AWK. Otóż danych wyjściowych, czy też plików wyjściowych. standardowo wzorzec dopasowuje się po kolei do każdej linii pliku wejściowego. Dla pewności przeczytajmy jeszcze raz po- Czy warto uczyć się języka AWK? przedni akapit i spójrzmy natychmiast na przykład Wielką zaletą AWK-a jest jego przenośność. AWK jest (nazwijmy nasz pierwszy program test1.awk)! (przynajmniej w swojej oryginalnej wersji) inter- $0=="TeX" { print $0 } preterem, a więc źródła programów AWK-owych i uruchommy AWK-a. Standardowo powinno wy- można z łatwością przenieść z UNIX-a na DOS-a lub glądać to tak 2 : gdziekolwiek indziej bez konieczności modyfikacji programu 1 . Z reguły jednak narzecza AWK-a mają nieco inne nazwy od oryginału np. GAWK, mawk itp. 1: Zdanie to jest prawdziwe, jeżeli poruszamy się 2: znak > symbolizuje prompt (znak zachęty) cały czas w obrębie tej samej implementacji AWK-a. systemu operacyjnego© Copyright by Grupa Użytkowników Systemu TEX 1996 http://www.GUST.org.pl
  • 2. 1996 GUST, Zeszyt 7 11 > awk -f test1.awk plik.we przykład 1 (Nelson H. F. Beebe)Co się stanie? AWK sprawdzi czy w pliku wej- Poniższy pomysłowy program przepisuje plik wejściowy zastępując kolejne puste linie, jedną pustą linią.ściowym plik.we istnieją linie zawierające napis(i tylko napis) TeX, a następnie wypisze je do NF == 0 { nb++ }standardowego wyjścia, czyli na ekran monitora. NF > 0 { if (nb > 0) print ""; Taki będzie efekt, spójrzmy teraz nieco bliżej nb = 0; print $0; }na powyższy przykład. Najpierw sprawy oczywi-ste: $0=="TeX" jest wzorcem, zaś { print $0 }jest akcją. Akcja wykona się tylko wtedy gdy waru- awk, gawk, nawk...nek $0=="TeX" jest prawdziwy, czyli gdy linijkaw pliku wejściowym symbolizowana przez $0 jest Istnieje wiele interpreterów AWK-a; w systemachnapisem TeX. Instrukcja print $0 oznacza, że UNIX-o podobnych, dostarczane razem z syste-AWK wypisze żądaną linijkę. mem, są one dziełem jego dostawcy. Istnieje też Program w języku AWK może zawierać wiele kilka wersji ogólnodostępnych, takich jak: GAWKpar „ wzorzec { akcja }”. Dla każdej linii pliku – firmowany przez Free Software Foundation czywejściowego obliczane są kolejne wzorce (w kolej- mawk Michaela Brennana.ności ich występowania w programie) i wykony- Różne implementacje AWK-a nie są w 100%wane akcje. Przykład 1 ilustruje program AWK-owy kompatybilne ze sobą. Ponadto wiele implementa-wykorzystujący 2 wzorce 3 . cji oferuje rozszerzenia w stosunku do standardu Zanim przejdziemy do bardziej szczegóło- (za standard przyjmujemy opis z [1]). W niniej-wych informacji o języku wymienimy kilka pod- szym artykule przedstawimy standard AWK-a orazstawowych reguł składni AWK-a. rozszerzenia oferowane przez interpreter GAWK Kolejne pary „ wzorzec { akcja }” muszą w wersji 3.0. Gorąco polecamy wszystkim tę imple- być oddzielone średnikami lub znakami nowej mentację AWK-a, którą sami używamy od kilku lat. linii. Implementacja GNU interpetera AWK, po- Akcje mogą składać się z wielu poleceń, wstała w 1986 r. dzięki pracy Paula Rubina które muszą być oddzielone średnikami lub i Jay Fenlason we współpracy z Richardem Stall- znakami nowej linii. manem i Johnem Woodsem. Została ona gruntow- Wzorzec lub akcja może zostać pominięty. nie zmieniona w 1989 r. przez Davida Truemana W wypadku braku wzorca akcja zostaje wy- i Arnolda Robbinsa. W styczniu 1996 r. ukazała się konana dla każdej linii pliku wejściowego. Je- wersja 3.0 interpretera GAWK, zawierająca kilka in- żeli pominiemy akcję, to AWK zastosuje akcję teresujących rozszerzeń w stosunku do standardu. domyślną, czyli { print $0 }. W dystrybucji znajduje się także ponad 300 stroni- W powyższym przykładzie AWK czyta dane cowy podręcznik ([4]), zawierający kompletny opisz jednego pliku wejściowego (plik.we) ale w ogól- języka i wiele ciekawych przykładów.ności możemy uruchomić AWK-a w następujący Uwagi: Opis rozszerzeń jest specjalnie oznaczonysposób: w tekście za pomocą pisma pochyłego. PRZEDSTAWIONE PRZYKŁADY SĄ PRZY- awk -f program plik1 plik2 ... GOTOWANE DO WYKONYWANIA W SYSTEMIEW takiej sytuacji AWK czyta po kolei linie z pliku1 , DOS. Użytkownicy UNIX-a, których zainteresuje pliku2 itd. dla wszystkich plików których nazwy nasz artykuł, nie powinni mieć większych pro-podano w linii komend. Pliki te są modyfikowane blemów ze zmianą tych fragmentów programów,wg programu z pliku program . które są „DOS-owo zorientowane”.3: Programy AWK-owe prezentowane we fragmen- Struktura pliku wejściowegotach tekstu rozpoczynących się słowem przykład,często zawierają konstrukcje języka jeszcze nie omó- Dla AWK-a dane wejściowe składają się z rekordów,wione. Jeżeli coś jest niezrozumiałe, czytaj dalej, które rozdzielone są separatorami RS. Standar-a po lekturze całego artykułu wróć do do tego dowo rekordem jest cała linia, czyli separatoremmiejsca – wszystko powinno być jasne. jest znak końca linii.
  • 3. 12 GUST, Zeszyt 7 1996 Rekordy podzielone są na pola, które roz- Wzorce BEGIN i END nie mogą być częścią wzorcadzielone są separatorami pól FS. Standardowo złożonego. Podobnie częścią wzorca złożonego nie możeseparatorem pól jest znak spacji lub tabulacji. być wzorzec z przecinkiem. RS i FS są zmiennymi, a więc można imnadać wartość. Przykładowo, jeśli zmiennej FS BEGIN/END. Wzorzec BEGIN nie pasuje do żad-nadamy wartość ‘;’, to spacje i tabulatory nie będą nej linii z pliku wejściowego, a odpowiadająca museparatorami pól lecz znaki ‘;’. akcja jest wykonywana przed przeczytaniem przez W akcjach i wzorcach, do wartości pól można AWK-a pierwszego znaku z tego pliku. Podobnieodwoływać się zmiennymi postaci $ nr-pola . Tak instrukcje wzorca END wykonywane są po prze-więc $1 to pierwsze pole rekordu, $2 drugie itd. czytaniu wszystkich znaków pliku wejściowego.$0 oznacza cały rekord. Wbudowana zmienna NF Możliwe jest umieszczenie wielu wzorców BEGINprzechowywuje liczbę pól bieżącego rekordu. i END w programie AWK-owym; są one wtedy wy- konywane po kolei. Z reguły użytkownicy AWK-a umieszczają wzorce BEGIN na początku a END naWzorce końcu pliku. Dla AWK-a jest to absolutnie obojętne.Wzorce służą do wyznaczenia tych linii tekstu, Jednym z najczęstszych sposobów użycia BE-dla których wykonane mają być odpowiednie GIN jest zmiana domyślnego sposobu w jaki AWKakcje. W ogólnym wypadku wzorzec może być dzieli linie czytanego pliku na pola. Wbudowanakombinacją wyrażeń logicznych i wyrażeń regu- zmienna FS definiuje jaki znak jest separatoremlarnych. Ponieważ wzorce są wyrażeniami logicz- pól w rekordzie. Domyślnie pola oddzielone sąnymi, dozwolone są operatory logiczne: &&, ||, znakami spacji lub/i tabulacji. Taki sposób dzielenia! oraz nawiasy. Istnieją dwa specjalne wzorce rekordu odpowiada sytuacji kiedy FS jest nadanao nazwie BEGIN i END. Oto ogólna specyfikacja wartość równa spacji (FS=" "). Przy uruchomieniuwzorców: programu zawierającego tylko wzorce BEGIN AWK nie oczekuje w linii komend nazwy żadnego pliku Wzorce wejściowego, por. przykład 10, s. 21.BEGIN{ akcja } Wyrażenie. Wzorcami mogą być wyrażenia aryt- akcja jest wykonywana przed otwarciem pliku wejścio- metyczne lub napisowe. Odpowiednia akcjawego. jest wykonywana za każdym razem gdy takieEND{ akcja } wyrażenie ma wartość różną od zera lub od na- pisu pustego. Przykłady: $3/$2 >= 10, NR < 9 czy akcja jest wykonywana po zamknięciu pliku wejścio-wego. "NY3".wyrażenie { akcja } Wzorzec regularny. Wzorzec regularny to wyraże-akcja jest wykonywana za każdym razem gdy wartość nie regularne ujęte w parę znaków /. Podstawowewyrażenia jest równa prawda tj. jest niezerowe (dla sposoby użycia wzorca regularnego to:wyrażeń numerycznych) lub niepuste (dla napisów). /r// wyrażenie-regularne /{ akcja } Pasuje do bieżącej linii pliku wejściowego jeżeli akcja jest wykonywana za każdym razem gdy linia zawiera ona podnapis pasujący do wyrażeniapliku wejściowego zawiera ciąg znaków pasujący do regularnego r. wyrażenia-regularnego . wyrażenie ~ /r/ wzorzec-złożony { akcja } Pasuje do napisu będącego wartością wyrażenia akcja jest wykonywany za każdym razem gdy linia czy- jeżeli zawiera on podnapis pasujący do wyrażeniatanego przez AWK pliku zawiera ciąg znaków pasującydo wzorca złożonego . regularnego r. Zapis /r/ jest równoważny formie $0 ~ /r/. wzorzec1 , wzorzec2 { akcja } wyrażenie !~ /r/ akcja jest wykonywana dla wszystkich linii od liniizawierającej wzorzec1 do linii zawierającej wzorzec2 Pasuje do napisu będącego wartością wyrażenia(łącznie z tymi liniami). Wzorzec oznacza wyrażenie jeżeli nie zawiera on podnapisu pasującego dobądź wyrażenie-regularne . wyrażenia regularnego r.
  • 4. 1996 GUST, Zeszyt 7 13Wzorzec złożony. Wzorzec złożony to wyraże-nie złożone z wzorców i operatorów logicznych c znak nie będący metaznakiem c znak sterujący albo znak/metaznak c||, &&, !. Wzorzec złożony pasuje do bieżącej . dowolny znaklinii pliku wejściowego jeżeli wartością wyraże- ^ początek napisunia jest prawda (czyli jest niezerowa lub niepusta). $ koniec napisuPrzykład: [ab...] dowolny ze znaków a, b... [^ab...] dowolny ze znaków oprócz a, b... $2 > 0.50 && $5 > 0.95 [a-z] dowolny ze znaków z zakresu a-z [^a-z] dowolny ze znaków oprócz a-zWzorzec z przecinkiem. Pasuje do wszystkich li- r1 |r2 r1 lub r2 (r oznacza wyrażenie regularne)nii, od linii pasującej do wzorca1 do linii pasującej r* zero lub więcej napisów pasujących do rdo wzorca2 (łącznie z tymi liniami). Przykład: r+ jeden lub więcej napisów pasujących do r /StartCharMetrics/,/EndCharMetrics/ r? zero lub jeden napis pasujący do r (r) r (nawiasy służą do grupowania wyrażeń)Wyrażenia regularne Grupę znaków ujętą w nawisy klamrowe na-Używając AWK-a nie sposób pominąć wyrażeń re- zywamy listą. Do takiego wyrażenia regularnegogularnych, które stanowią o sile tego języka. Nie pasuje jeden dowolny znak z listy. Zakres znakówbędziemy przytaczać ścisłej matematycznej defini- to dwa znaki ujęte w nawiasy klamrowe oddzie-cji, gdyż zaciemnilibyśmy tylko bardzo intuicyjne lone znakiem - (minus). Zakresy interpretowanei łatwe naszym zdaniem pojęcie. są według kolejności wartości kodów ASCII ja- Siła wyrażeń regularnych polega na możli- kie posiadają poszczególne znaki. Zatem specy-wości stosowania uniwersalnych wzorców, które fikacja [0-9] jest równoważna [0123456789],pasują (opisują) pewien zbiór napisów. Na pewno zaś [A-Da-d] liście [ABCDabcd].każdy z nas wydał polecenie swojemu systemowi Dopełnieniem listy/zakresu jest lista/zakresoperacyjnemu, w którym zawarty był znak *; na z poprzedzającym znakiem ^ (bezpośrednio poprzykład: otwierającym nawiasie [). Przykładowo specyfi- > emacs *.tex kacja [^0-9] oznacza jeden dowolny znak aleJeśli nie zdarzyło Ci się wydać takiego polecenia, nie cyfrę; [^A-ZĄĆĘŁŃÓŚŹ ] dowolny znak nieto już wyjaśniamy! emacs to popularny edytor będący dużą literą alfabetu.tekstowy, zaś napis *.tex oznacza, że chcemy Wewnątrz listy/zakresu wszystkie znaki opróczedytować wszystkie pliki z rozszerzeniem .tex 4 , ^, - tracą swoje metaznaczenie. Przykładowo:z bieżącego katalogu. Znak * jest właśnie wyraże- [...] oznacza trzy kropki (a nie trzy dowolneniem regularnym, które oznacza w tym wypadku znaki) zaś ^[^^] wszystkie znaki oprócz znaku ^dowolną (z dokładnością do ograniczeń naszego na początku napisu.systemu operacyjnego) ilość i rodzaj znaków. Nawiasy okrągłe służą do grupowania. Przy- Wyrażenia regularne to wyrażenia umożliwia- kładowo: /(X|XX)(I|II|III)/ pasuje do na-jące specyfikowanie klas napisów. O napisie nale- stępujących liczb XI, XII, XIII, XXI, XXII, XXIII.żącym do tej klasy mówimy, że pasuje do wyraże- Znaki sterujące, zapisujemy w konwencji ję-nia regularnego. Wyrażenia regularne są konstru- zyka C. Są to: a (dzwonek, alarm), b (znakowane z następujących elementów: „normalnych cofnięcia, backspace), f (znak końca strony, formznaków” (wszystkie litery, cyfry, większość pozo- feed), n (przejście do nowego wiersza, new line),stałych znaków) oraz metaznaków , ^, $, ., [, r (carriage return), t (znak tabulacji). Ponadto], |, (, ), *, +, ?. Poniższa tabela przedstawia znak oznacza , zaś każdy znak możemy za-poszczególne elementy wyrażeń regularnych. pisać przy pomocy kodu ósemkowego używając konwencji cyfra cyfra cyfra . Wyrażenia regularneWyrażenie Znaczenie przykład 2 (wyrażenia regularne) /^[ t]*$/ pasuje do napisu składającego się tylko ze znaków spacji, tabulacji i napisu pustego;4: Czyli takie pliki, których nazwa kończy się /^[^ t]*$/ pasuje do wszystkich napisów opróczznakami .tex. składających się ze spacji, znaków tabulacji i pustych;
  • 5. 14 GUST, Zeszyt 7 1996 /[+-]?[0-9]+[.]?[0-9]*/ pasuje do liczby rze- NR liczba przeczytanych rekordówczywistej ze znakiem; OFMT specyfikacja formatu dla liczb /[A-Za-z]+/ pasuje do ciągu liter poprzedzo- OFS separator pól na wyjściu, por. s. 23nych znakiem (np: komenda TEX-owa). ORS separator rekordów na wyjściu, por. s. 23 RLENGTH por. opis funkcji match, s. 16 RS separator rekordówWyrażenia RT napis pasujący do wyra enia RS, por. 21Podstawą składni wyrażeń AWK-a jest popularna RSTART por. opis funkcji match, s. 16 SUBSEP separator indeksów tablic, por. s. 19składnia wyrażeń języka C. Składnia ta zostaław AWK wzbogacona o operacje tekstowe. ENVIRON jest tablicą przechowującą wartości zmien- Elementami wyrażeń są: stałe, zmienne, ope- nych środowiskowych. Indeksami są nazwy zmiennych,ratory, funkcje wbudowane i definiowane przez wartościami zaś napisy zawierające wartości tych zmien-użytkownika oraz elementy tablic asocjacyjnych. nych. Przykładowo:Omówimy je po kolei. ENVIRON["TEXCONFIG"] W AWK-u istnieją tylko dwa typy danych: licz-bowy i napisowy. Zmienne liczbowe przechowują mo e zawierać, np: .;texdvips;gslibpsfontswartości zmiennopozycyjne, przy czym ich do- AWKPATH – nazwa zmiennej środowiskowej zawierają- cej ście ki dostępu do katalogów zawierających programykładność zależna jest od implementacji. Zmienne AWK-owe (czyli pliki *.awk) Je eli zmiennej AWKPATH nienapisowe przechowują oczywiście ciągi znaków nadano adnej wartości (poleceniem SET w systemie DOS)czyli napisy. Zmiennych nie deklaruje się. Typ to jest ona równa ".;c:/lib/awk;c:/gnu/lib/awk".zmiennej określony jest przez kontekst; w razie ERRNO udostępnia napis zawierający systemowy komu-potrzeby zawsze dokonywana jest odpowiednia nikat błędu, je eli przy wykonaniu funkcji getline lubkonwersja. Zmienna nie zainicjowana ma wartość close wystąpi błąd. Przykładowo, po wykonaniu:zero lub "" (pusty napis). Stałe liczbowe zapisu- getline < "qq.qq.qq"jemy jak w C, tj. 3.1415 lub 1.333e-5, stałe ERRNO zawiera "No such file or directory".napisowe otacza się znakami ". IGNORECASE określa czy AWK rozró nia du e i małe Istotny jest także sposób interpretacji wyra- litery przy porównywaniu napisów oraz wyra eń regular-żeń numerycznych i tekstowych w operacjach nych. Je eli IGNORECASE jest niezerowe/niepuste, wtedylogicznych. Fałsz odpowiada liczbie 0 i napisowi operatory ~, !~ oraz funkcje gensub, gsub, index, match, split oraz sub nie rozró niają du ych i małychpustemu "", zaś prawda odpowiada wszystkim liter. Dotyczy to tak e wartości zmiennych wbudowanychinnym liczbom i napisom. RS i FS. GAWK począwszy od wersji 3.0 obsługuje normęZmienne wbudowane. Większość zmiennych zo- ISO-8859-1 (tj. ISO Latin-1). Standard ten nie zawiera jednak większości polskich znaków diakrytycznych.stała lub zostanie dokładnie omówiona przy okazji ARGIND przechowuje indeks pod którym, w tablicyomawiania tych aspektów AWK-a, których dotyczą. ARGV znajduje się nazwa przeglądanego pliku. Zawsze jestOto zestawienie wszystkich zmiennych: prawdziwa równość FILENAME == ARGV[ARGIND]. Zmienne wbudowane Uwagi: Zmienna FILENAME zawiera nazwę bieżą-Zmienna Opis znaczenia cego pliku wejściowego. Oznacza to, że w obrę-ARGC liczba argumentów wywołania bie wzorców BEGIN i END wartość FILENAME jest programu nieokreślona.ARGV tablica argumentów wywołania programu Operatory arytmetyczne. Operatory arytmetyczneARGIND index w ARGV odpowiadający są naszym zdaniem łatwe i intuicyjne: bie ącemu plikowiENVIRON tablica zmiennych środowiskowych Operatory arytmetyczneERRNO napis z systemowym opisem błęduFIELDWIDTHS specyfikacja długości pól, por. s. 22 Postać wyrażenia Opis znaczeniaFILENAME nazwa bieżącego pliku wejściowego * iloczynFNR numer bieżącego rekordu + suma w bieżącym pliku - różnicaFS separator pól / ilorazIGNORECASE przełącznik rozró niania wysokości liter % moduloNF liczba pól w bieżącym rekordzie ^ potęga
  • 6. 1996 GUST, Zeszyt 7 15++ inkrementacja Samotnie pojawiające się na przykład w ak-– dekrementacja cji wyrażenie /TeX/ jest równoważne w AWK wyrażeniu $0 ~ /TeX/.Operatory napisowe. Napisy i zmienne napi- przykład 3sowe można łączyć (konkatenować) przy po- Zaimplementujmy funkcję, zwracającą 1 jeżeli rok jestmocy „niewidocznego” operatora – po prostu przestępny, lub 0 dla lat nieprzestępnych. Algorytmnależy umieścić napisy obok siebie. Przykładowo cytujemy za [3], s. 121.po wykonaniu: function leapyear(year) { return year %4 == 0 && year % 100 y = "Ali"; x = y "ba" "ba" != 0 || year%400 ==0; }zmienna x ma wartość "Alibaba". Oprócz ope-racji konkatenacji AWK nie ma żadnych innych BEGIN {print leapyear(1996), leapyear(1806), leapyear(1066)}operatorów napisowych. Wzorzec BEGIN jest oczywiście potrzebny tylko dlaOperatory porównywania i operatory logiczne. testowania funkcji. Jeżeli powyższy kod umieścimyZapis i działanie operatorów w AWK-u w wypadku np. w pliku lyear.awk to pisząc gawk -f lyear.awkzmiennych typu liczbowego jest identyczny jak otrzymamy na ekranie:w języku C. Nowością AWK-a jest to, że mogą być 100także stosowane do napisów. Uwagi: Bardzo długa instrukcja może zostać podzielona i zapisana w kilku linijkach. Znakiem kontynuacji jest , Operatory porównywania bezpośrednio przed znakiem końca linii (por. drugą linijkę przykładu). Jeżeli linijka kończy się przecinkiemOperator Opis znaczenia (por. linijka przedostatnia) to znak kontynuacji jest== równe opcjonalny.!= różne< mniejsze Przypisanie. Przypisanie oznaczane jest w AWK-u<= mniejsze lub równe pojedynczym znakiem równości =. Podobnie jak> większe>= większe lub równe w języku C operator ten nadaje zmiennej wartość i zwraca przypisaną wartość, stąd dozwolone są Napisy są porównywane w taki sposób, że wyrażenia postaci x = y = 1 lub (x = y) <= 1.najpierw porównywane są pierwsze znaki, po- Z operatorem przypisania związane są ope-tem drugie itd. Przykładowo: "10" jest mniejsze ratory modyfikacji: +=, -=, *=, /=, %=, /= i ^=.od "9". Jeżeli jeden napis jest przedrostkiem dru- Przykładowo wyrażenie x += y jest tożsame z xgiego to krótszy napis jest mniejszy od dłuższego, = x + y, wyrażenie x -= y jest tożsame z x = x -np. Ali jest mniejsze od "Alibaba". Oczywiście y itd.prawdą jest: "TeX" == "TeX". Operator warunkowy ?:. Operator warunkowy Operatory logiczne ?: posiada następującą składnię:Operator Opis znaczenia wyrażenie1 ? wyrażenie2 : wyrażenie3&& suma logiczna Najpierw obliczane jest wyrażenie1 . Jeśli jest ono|| alternatywa prawdziwe obliczane jest wyrażenie2 , w przeciw-! zaprzeczenie nym wypadku wyrażenie3 . Poniższy program oblicza i drukuje odwrot-Operatory związane z dopasowywaniem wyrażeń ność pierwszych pól wszystkich rekordów, spraw-regularnych. Ostatnia grupa to operatory zwią- dzając czy $1 nie jest równe zeru:zane z dopasowywaniem wyrażeń regularnych, są {print $1!=0 ? 1/$1 : "Zero w linii", NR;}one specyficzne dla języka AWK. Mamy tylko dwa takie operatory ~ oraz Arytmetyczne funkcje wbudowane!~. Umożliwają one dopasowanie zmiennej dopewnego wyrażenia regularnego. Przykładowo AWK oferuje inny zestaw funkcji wbudowanych$1 ~ /TeX/ jest prawdziwe, gdy pierwsze pole niż język C. Funkcje wbudowane mogą być,rekordu zawiera napis TeX. bez żadnych ograniczeń, elementami wyrażeń.
  • 7. 16 GUST, Zeszyt 7 1996Oto lista takich funkcji (niech x, y będą pewnymi wszelkiego rodzaju zmiany kontekstowe, por. przykład 5.wyrażeniami): Symbol 0 oznacza całe wyra enie regularne r 5 . Poni szy przykład wyjaśnia znaczenie argumentu a : Funkcje arytmetyczne BEGIN{ t = "Alibababa";Funkcja Wartość funkcji print gensub(/ba/, "BA", 2, t) }atan2(y,x) arcus tangens z y/x w zakresia −π do π otrzymamy: AlibaBAbacos(x) cosinus z x, x w radianach index( s , t )sin(x) sinus z x, x w radianach Zwraca numer pierwszego znaku napisu t w napisieexp(x) eksponent, czyli funkcja wykładnicza ex s . Jeżeli s nie zawiera t zwracana jest wartość zero.int(x) część całkowita z x Pierwszy znak w napisie ma numer 1. Przykładowo:log(x) logarytm z x przy podstawie e index("Alibaba", "baba")sqrt(x) pierwiastek kwadratowy z x zwraca 4;rand() przypadkowa liczba z przedziału 0, 1) length( s )srand(x) x jest wartością początkową dla Podaje długość napisu s . generatora liczb pseudolosowych match( s , r ) Jeżeli s zawiera podnapis pasujący do r , to zwraca Używając powyższych funkcji można uzy- numer pierwszego znaku tego podnapisu; w przeciw-skać użyteczne liczby, na przykład π lub e; nym razie zwracane jest 0. Ponadto nadawane są war-atan2(0, −1)= π oraz exp(1)= e. Również uzyska- tości zmiennym RSTART oraz RLENGTH. RSTART jestnie logarytmu dziesiętnego nie jest problemem, równe wartości zwracanej przez funkcję, RLENGTH jest równe długości podnapisu pasującego do r .jeśli zastosujemy wzór log(x)/ log(10). split( s , a , fs ) Podstawienie Z napisu s tworzy tablicę napisów a w oparciu randint = int(n * rand()) + 1 o znak separujący fs . Jeżeli split wywołamy tylkospowoduje nadanie zmiennej randint wartości z dwoma parametrami to znakiem separującym jest znak określony wartością zmiennej FS, czyli separatorz przedziału 1, n . pól w rekordzie. sprintf( format , lista-wyra eń)Napisowe funkcje wbudowane Zwraca napis, sformatowany według napisu format , por. funkcja printf, s. 22.Poniższe zestawienie zawiera funkcje AWK-a umoż- sub( r , s , t )liwiające manipulowanie napisami. W zestawieniu Najdłuższy napis pasujący do wyrażenia regularnego r oznacza wyrażenie regularne, s i t napis. r zamienia na napis s w napisie t (lub w $0 jeżeli wywołana jest tylko z dwoma pierwszymi parametrami Funkcje napisowe – podobnie jak gsub). Zwracana jest liczba dokonanychgsub( r , s , t ) zamian.Zamienia wyrażenie regularne r na napis s w napisie substr( s , p , n ) t . Zwracana jest liczba zamian. Jeżeli gsub wywołamy Zwraca napis wycięty z s począwszy od pozycji ptylko z dwoma pierwszymi parametrami to zmiany o długości n znaków (lub do końca napisu s ,dokonywane są w napisie $0. (tj. gsub( r , s ) jest jeżeli ostatni argument jest pominięty). Przykładoworównoważne gsub( r , s ,$0)). wykonanie instrukcjigensub( r , s , a , t ) print substr("Alibaba",4);Uogólniona funkcja gsub. Zwraca zmieniony napis (nie spowoduje wydrukowanie napisu „baba”.modyfikuje oryginalnego napisu t !). Zamienia wyra enieregularne r w oparciu o napis s , w napisie t (je elinie ma t , domyślnym argumentem jest $0). Argument 5: W chwili pisania tego tekstu funkcja gensub jest zaim- a określa, który z kolei podnapis pasujący do wyra enia plementowana z błędem. Mianowicie, je eli w tekście t r ma być wymieniony. Je eli a jest napisem rozpoczy- nie ma napisu pasującego do r , to zwracana jest, zamiastnającym się od "g" (lub "G") to wymieniane są wszystkie niezmienionego napisu t , liczba 5.9976e-315. Autorzynapisy pasujące do r . Funkcja gensub umo liwia wsta- nie natknęli się na inne błędy, i w związku z tym wydajewienie fragmentów wyra enia regularnego w napisie s . się bezpieczne stosowanie tej funkcji połączone z te-Je eli wyra enie r podzielimy za pomocą nawiasów, ( stowaniem zwracanej wartości, np. mo na zdefiniowaći ) na części składowe to te składowe mogą później poja- następującą funkcję xgensub:wić się w napisie s (oznaczamy je jako n , gdzie n xgensub(r, s, a, t, tmp){jest cyfrą od 1 do 9. Znaczenie tego jest takie, e napis tmp = gensub(r, s, a, t);pasujący do n -tej składowej jest kopiowany, z tekstu t return tmp == 5.9976e-315 ? t : tmpdo tekstu zwracanego przez funkcję. W efekcie mo liwe są }
  • 8. 1996 GUST, Zeszyt 7 17tolower( s ) char = big[j]Zwraca napis, w którym du e litery zostały zamienione na j = ALPHABET + 1;małe. W wypadku tekstów polskich funkcja ta ma ogra- }}niczone zastosowanie, nie zamieni bowiem liter z górnej newstring = newstring char;połówki tabeli ASCII, gdzie znajdują się Ą, Ć, Ę, itd. }toupper( s ) return newstringZwraca napis, w którym małe litery zostały zamienione na }du e. Z „polskiego” punktu widzenia ma tę samą wadę cotolower. BEGIN{ LOWER = "abcdefghijklmnopqrs tuvwxyząćęłńóśź "; UPPER = "ABCDEFGHIJKLMNOprzykład 4 (fragment spj.awk, pomysł M. Ryćko) PQRSTUVWXYZĄĆĘŁŃÓŚŹ "; # wymień co w kontekście bef aft na na ALPHABET = length(LOWER); function exch (bef, co, aft, na) { while (match(para, bef co aft) > 0) { for (i = 1; i <= ALPHABET; i++){ match(para, bef co aft); little[i] = substr(LOWER,i,1) nowy = substr(para, 1, RSTART) na big[i] = substr(UPPER,i,1) substr(para, RSTART+RLENGTH-1); } para = nowy; } } Dodajmy jeszcze następujący wzorzec BEGIN: } BEGIN { print upper("Tó jęśt tęśtć"); }Powyższa funkcja 6 realizuje kontekstową zamianę frazy Uruchamiając AWK-a. Otrzymamy na ekranie:na frazę. Jest namiastką tego czego AWK-owi do tej porybrakowało (por. nast. przykład) – zamiany wyrażenia TÓ JĘŚT TĘŚTĆregularnego na wyrażenie regularne. Zakładamy, że fraza bef jest jednoznakowa i po- Funkcje daty i czasuprzedza co , zaś fraza aft następuje po co i także jestjednoznakowa. Przykład użycia: Interpreter GAWK od wersji 3.0 oferuje dwie funkcje doty- czące daty i czasu. Są to systime i strftime: { exch("[0-9]","-","[0-9]", "–"); print } systime()wymieni w całym tekście wszystkie frazy cyfra - cyfra Zwraca bie ący czas w sekundach jakie upłynęły od po-na cyfra – cyfra czyli na przykład 1992-1993 zamieni czątku epoki. W standardzie POSIX jest to liczba sekundna 1992–1993. od 1 Stycznia 1970 r. strftime( format , czas )przykład 5 (GAWK3.0) Zwraca napis zawierający czas (liczba w takim samymPoni szy programik wykorzystujący funkcję gensub: formacie jak wartość zwracana przez systime) sformato- { $0=gensub(/([0-9])-([0-9])/, wany według specyfikacji zawartych w napisie format . "1–2", "g",$0) Forma krótka strftime() oznacza u ycie formatu "%a print %b %d %H:%M:%S %Z %Y" oraz bie ącego czasu. Forma } strftime( format ) wypisuje bie ący czas według spe- cyfikacji z formatu .robi to samo co funkcja exch czyli zamienia w całym tek- Specyfikacje przekształceń funkcji strftime są zgo-ście wszystkie frazy cyfra - cyfra na cyfra – cyfra , dne ze standardem ANSI C. Ka da specyfikacja składa sięnp. s.~1-11 zmieni na s.~1–11. ze znaku „%” oraz następującego po nim znaku określa- jącego typ konwersji (por. tak e funkcja printf, s. 22)przykład 6 (zamiana małych liter na duże) Nie będziemy podawać pełnej listy znaków konwersjiPoniższa funkcja jest odpowiednikiem funkcji toup- (por. [4], s. 149–151), ograniczymy się do najczęściejper; ma tę zaletę, że „rozpoznaje” polskie znaki. Ła- stosowanych:two też daje się modyfikować dla różnych wariantówkodowania polskich znaków. Znaki konwersji function upper(string, i, j){ Znak Typ przekształcenia newstring = "" for (i = 1; i <= length(string); i++){ d dzień miesiąca (01–31) char = substr(string, i, 1) H godzina w zapisie 00–23 for (j = 1; j <= ALPHABET; j++){ I godzina w zapisie 01–12 if (char == little[j]){ j dzień roku (001–366) m miesiąc (01-12) M minuta (00–59)6: Porównaj punkt Funkcje dalej w tekście. S sekundy (00–61)
  • 9. 18 GUST, Zeszyt 7 1996 y rok w zapisie dwucyfrowym (00-99) break Y rok w zapisie czterocyfrowym (np. 1066) natychmiastowe wyjście z pętli while, for, do continue kontynuacja iteracji w pętlach while, for, doInstrukcje sterujące nextAWK pozwala nam grupować instrukcje, podejmo- rozpoczęcie następnej iteracji głównej pętli wejściowej 7wać decyzje (konstrukcja if-else) oraz tworzyć exit wyrażeniepętle (instrukcje for, while). Składnia tych sterowanie jest przekazywane bezpośrednio do akcji END. Jeśli komendy exit użyto w akcji END, programinstrukcji pochodzi bezpośrednio z języka C. kończy definitywnie działanie. Opcjonalne wyrażenie Pojedyncza instrukcja może być zawsze za- zwracane jest jako status programu.stąpiona listą instrukcji ujętych w nawiasy grupu- nextfilejące. Na liście instrukcje separowane są końcami zakończenie przeglądania bie ącego pliku i przejście dolinii lub średnikami. Znaki końca linii mogą poja- przeglądania następnego z podanych w linii komend, lubwić się po dowolnym lewym i przed dowolnym (dla ostatniego pliku) przejście do wzorca END. W wy-prawym nawiasem grupującym. niku wykonania nextfile zmienia się wartość zmiennej Spójrzmy przykładowo na składnię instrukcji FILENAME, wartością FNR staje się jeden oraz wartość ARGIND jest zwiększana o jeden.if-else if ( wyrażenie ) Instrukcja pusta. Jeśli w linijce programu AWK- instrukcja1 -owego umieścimy samotny znak ‘;’, to otrzy- else mamy instrukcję pustą. Spójrzmy na poniższy instrukcja2 program wykorzystujący taką instrukcję w pę-część else instrukcja2 jest opcjonalna. tli for; program drukuje wszystkie linie, które W celu uniknięcia dwuznaczności przyjęto, zawierają puste pole.że każdy else jest w parze z bezpośrednio BEGIN { FS = "t" }poprzedzającym go if-em; przykładowo { for (i=1; i<=NF && $i-""; i++) if (e1) if (e2) s=1; else s=2 ;tu else jest w parze z drugim if-em. (Średnik if (i<=NF) { print }po s=1 jest wymagany, gdyż else znalazł się }w jednej linii z if-em.) Tablice asocjacyjne Instrukcje sterujące Tablice asocjacyjne to jedyny rodzaj tablic do-{ instrukcje }grupowanie instrukcji stępny w AWK-u. Tablic nie trzeba deklarować, określać ich wymiarów czy typu elementów skła-if ( w ) instrukcjajeśli wyrażenie w jest prawdziwe, wykonaj instrukcję dowych. Utworzenie elementu tablicy następuje w chwili wykonania podstawienia, np. a[44]if ( w ) instrukcja1 else instrukcja2Wykonaj instrukcję1 jeśli wyrażenie w jest praw- = 3.14 lub a[1]="Alibaba", albo innego od-dziwe, w wypadku przeciwnym instrukcję2 wołania do niego. Element nie zainicjowany jestwhile ( w ) instrukcja równy zero lub równy napisowi pustemu. Indeksyjeśli wyrażenie w jest prawdziwe, wykonaj instrukcję nie są liczbami ale napisami. Użycie w kontekściei powtórz indeksu liczby spowoduje jej konwersję do od-for ( w1 ; w2 ; w3 ) instrukcja powiedniego napisu. Trzeba o tym pamiętać, np.równoważne instrukcji: print a["01"] nie spowoduje wydrukowania w1 ; while ( w2 ) { instrukcja ; w3 } słowa Alibaba (tylko przypuszczalnie napis pu-for ( zmienna in tablica ) instrukcja sty) – napisy "1" oraz "01" są oczywiście różne, instrukcja jest wykonywana dla zmiennej przyjmującej podczas gdy liczby nie.kolejno wartości każdego elementu tablicydo instrukcja while ( w ) 7: Przez główną pętlę wejściową rozumiemy mecha-wykonywana jest instrukcja jeśli wyrażenie w jest nizm AWK-a do analizowania rekord po rekordzie plikuprawdziwe i powtórz wejściowego.
  • 10. 1996 GUST, Zeszyt 7 19 Poniższy program zapamiętuje wszystkie sło- for (i=1; i<=10; i++)wa pliku wejściowego oraz liczbę ich wystąpień. for (j=1; j<=10; j++) {for (i=1; i<=NF; i++) {ls[$i]++}} r[i,j] = rand();Zwróćmy uwagę, że za każdym razem, gdy poja- zostanie utworzona tablica 100 elementów, dowia się nowy wyraz, AWK tworzy nowy element których możemy się odwoływać za pomocą partablicy z wartością początkową 0. Następnie ope- zmiennych indeksowanych postaci i,j. Wewnętrz-rator inkrementacji nadaje mu wartość 1. Każde nie jednakże poszczególne elementy tablic są in-następne pojawienie się tego wyrazu powoduje deksowane za pomocą napisów postaci i SUBSEPzwiększenie wartości już istniejącego elementu. j. Zmienna wbudowana SUBSEP przechowuje Powstaje problem jak dobrać się do poszcze- znak używany do oddzielenia indeksów składo-gólnych elementów tablicy ls, skoro nie znamy wych; standardową wartością tej zmiennej nie jestwartości indeksów (wyrazów tekstu). Do tego celu przecinek ale znak "034". Sposób testowania czysłuży specjalna forma pętli for: element i,j należy do tablicy nie zmienia się: for ( zmienna in tablica ) for ((i,j) in r) {...} instrukcja zaś w wypadku pętli for piszemy: zmienna przyjmuje iteracyjnie wszystkie warto- for (k in r) {print r[k]}ści indeksów tablicy . Kolejność przeglądaniatablicy nie jest ustalona i jest zależna od kon- Uwagi: Elementy tablic nie mogą być tablicami.kretnej implementacji AWK-a. Działanie pętli jestnieokreślone jeżeli wewnątrz pętli zostaną dodane Funkcjekolejne elementy do tablicy . Chcąc wydrukować AWK umożliwia definiowanie własnych funkcji.listę słów z naszego przykładu możemy posłużyć Definicja funkcji może być umieszczona w do-się następującą akcją z wzorcem END: wolnym miejscu programu, pomiędzy kolejnymi END {for (word in ls) parami wzorzec-akcja. Funkcje są definiowane print word, ls[word] następująco: } function nazwa ( lista-argumentów ) { Wyrażenie lista-instrukcji indeks in tablica }pozwala ustalić czy określony indeks występuje lista-argumentów to ciąg oddzielonych przecin-w tablicy . Jeżeli występuje to wartością wyrażenia kami argumentów funkcji. Podczas wywołaniajest 1, w wypadku przeciwnym 0. Przykładowo, funkcji, argumentom nadawane są odpowied-poniższa instrukcja sprawdza czy w tablicy ls nie wartości. Nazwy argumentów są lokalnewystąpiło słowo TeX: dla funkcji; są one przekazywane przez war- if ("TeX" in ls) {print "OK!"} tość, z wyjątkiem tablic, które są przekazywane else {print "KO!"} „przez referencję”. Argumenty funkcji są jedynymi zmiennymi lokalnymi w AWK-u.delete. Element tablicy możemy usunąć za po- Lista-instrukcji może zawierać instrukcje re-mocą instrukcji: turn wyrażenie . Wykonanie return polega na delete tablica [ indeks ] obliczeniu wartość wyrażenia , a następnie prze- kazaniu tej wartości w miejsce wywołania funkcjiprzykładowo delete ls["TeX"] usuwa z tablicy (tzw. wartość zwracana przez funkcję). Wyrażeniels element odpowiadający indeksowi "TeX". jest opcjonalne – jeżeli go nie ma, instrukcjaTablice wielowymiarowe. Tablice wielowymia- return jedynie przekazuje sterowanie do miej-rowe są symulowane przez AWK-a za pomocą sca wywołania. Jeżeli wśród listy-instrukcji nietablic jednowymiarowych. Z punktu widzenia ma return to po wykonaniu ostatniej instrukcjiużytkownika nie ma to wielkiego znaczenia. (przed zamykającym nawiasem klamrowym) ste-Przykładowo w wyniku działania poniższego rowanie jest przekazywane do miejsca wywołania,fragmentu programu: a wartość zwracana jest nieokreślona. Zilustrujmy
  • 11. 20 GUST, Zeszyt 7 1996to prostym przykładem funkcji max zwracającej Jeżeli nie podamy pliku wejściowego to AWK bę-większy ze swoich dwu argumentów ([1], s. 53): dzie czekał na strumień danych ze standardowego function max(x, y) { wejścia (klawiatury). Często jest to działanie nie- return x > y ? x: y zamierzone – ^C, ^break czy ^Z kończą działanie } programu w takiej sytuacji. Funkcje zdefiniowane za pomocą polece- Pola. Standardową wartością wbudowanej zmien-nia function mogą być użyte w dowolnym nej FS jest " " (spacja – odstęp). W takiej sytuacjiwyrażeniu, a także wewnątrz innych funkcji; poszczególne pola są rozdzielone odstępami lubdozwolona jest także rekursja (por. przykład 7). znakami tabulacji. Sposób rozdzielania pól możnaPrzy wywołaniu funkcji nie można umieszczać od- zmienić przypisując zmiennej FS odpowiedni na-stępu pomiędzy jej nazwą a rozpoczynającym listę pis. Jeżeli napis ten jest dłuższy niż jeden znak toargumentów nawiasem (. AWK traktuje go jako wyrażenie regularne. Najdłuż- Jak już mówiliśmy tylko argumenty funcji są sze (leftmost longest) ciągi znaków, nie zachodzącezmiennymi lokalnymi. Wszystkie inne zmienne na siebie (non overlaping), pasujące do tego wyraże-są globalne. Jeżeli chcemy aby AWK „widział” ja- nia regularnego będą odzielać poszczególne polakąś zmienną tylko lokalnie to jedyną metodą w bieżącej linii. Przykładowo deklaracja:jest umieszczenie jej na liście parametrów przy BEGIN {FS ="[,;:]"}definiowaniu funkcji. Po prostu nadmiarowe pa- powoduje, że pola będą rozdzielane przecinkiem,rametry umieszczamy na końcu listy. Nie będą średnikiem lub dwukropkiem. Kiedy wartością FSone wykorzystywane do przekazywania wartości, jest pojedynczy znak (inny od odstępu) to ten znaklecz będą stanowić dodatkowe zmienne lokalne. jest używany do rozdzielania pól.Wywołanie funkcji z mniejszą od deklarowa- Uwagi: Wartość zmiennej FS może zostać nadananej liczbą parametrów jest w AWK poprawne także z poziomu uruchomienia AWK-a za pomocą– wszystkie nadmiarowe parametry przyjmują przełącznika -F. Przyładowo zamiast powyższegowartości zerowe. wzorca BEGIN moglibyśmy napisać w linii komendprzykład 7 (system DOS):Następująca funkcja rekurencyjna odwraca napis poczy- gawk -F[,;:] -f prog.awk plik.wenając od znaku s ([4], s. 151).function rev(str, s) { Rekordy. Wartość zmiennej RS przechowuje znak if (s == 0) używany przez AWK-a do oddzielania poszczegól- return "" nych rekordów. Standardowo rekordy są oddzie- return (substr(str, s, 1) rev(str, s-1)) lane znakami końca linii (co odpowiada przypi-} saniu RS="n"). W ograniczony sposób możemyDla wypróbowania dopiszmy następujący prosty pro- zmienić sposób w jaki AWK wyróżnia poszczególnegram: rekordy, nadając odpowiednią wartość zmien-BEGIN {print rev("Vrooom",length("Vrooom"))} nej RS. W opisie [1] separatorem rekordu możeZakładając, że funkcja rev i wzorzec BEGIN znajdują być tylko napis jednoznakowy lub napis pusty.się w pliku rev.awk piszemy teraz gawk -f rev.awk.Na ekranie powinno się pojawić: Jeżeli RS="" (napis pusty) wtedy, separatorami rekordów są puste linie (jedna lub więcej).mooorV przykład 8 Wstawianie tyld (podejście naiwne) W zadaniu wstawienie tyld po spójnikach naturalnymWejście wydaje się podejście, przy którym rekordem jest cały akapit (odpada problem spójników kończących linijkę):AWK może czytać dane wejściowe na kilka sposo- BEGIN {RS=""; FS="n"; }bów. Najprostszym jest uruchomienie go w stan- { gsub(/[ t]+i[ t]*n/,"ni ");dardowy sposób czyli, np: gsub(/ni[ t]+/,"ni~"); gawk -f prog.awk plik.we gsub(/[ t]+i[ t]+/," i~"); itd. dla wszystkich spójnikówW takim kontekście, zgodnie z tym co już napisano print;we wstępie, AWK czyta plik plik.we linia po linii. }
  • 12. 1996 GUST, Zeszyt 7 21Wadą tego podejścia jest to, że długie akapity mogą getline. Funkcja getline umożliwia czytanie da-przekroczyć możliwości pamięciowe AWK-a. nych z bieżącego lub/i z innego pliku tekstowego Począwszy od wersji 3.0 GAWK-a, separator rekordu albo z potoku generowanego przez inny program.mo e być wyra eniem regularnym. W takiej sytuacji, ka dy Poniżej zestawiono różne formy użycia getline.napis pasujący do tego wyra enia wyznacza koniec kolej-nego rekordu (z tym, e napis ten nie jest częścią tego getlinerekordu, podobnie jak w wypadku gdy separatorem jest Postać instrukcji Inicjalizowane zmiennepojedynczy znak. getline $0, NF, NR, FNR Je eli RS jest wyra eniem regularnym wtedy zmienna getline z z , NR, FNRRT przechowuje dla bie ącego rekordu, napis będący jego getline < plik $0, NFseparatorem od rekordu następnego. getline z < plik z program | getline $0, NFprzykład 9 (edytor potokowy) program | getline z zNastępujący program ([4], s. 240–241) jest AWK-owąimplementacją edytora potokowego, tj. takiego programu, plik i program to zmienna lub stała napisowa zawiera-który czyta strumień danych, modyfikuje go i wysyła jąca odpowiednio nazwę pliku lub programu z któregodalej. Poni sza implementacja wyró nia się oryginalnością AWK ma czytać strumień danych.pomysłu. Sposób u ycia jest następujący: Dwie pierwsze formy dotyczą czytania da- gawk -f awksed.awk co naco plik1 plik2 ... nych z bieżącego pliku, dwie następne z pliku .Spowoduje zastąpienie frazy (wyra enia regularnego) co Dwie ostatnie to wczytywanie danych ze strumie-na napis naco (oba argumenty są wymagalne), w plikach nia generowanego przez inny program . Funkcja plik1 plik2 .... Je eli nie podamy listy plików dane getline zwraca wartość 1 jeżeli wczytana zostałabędą czytane ze standardowego wejścia. następna linia tekstu (rekord), 0 jeżeli napotkano# A. Robbins, arnold@gnu.ai.mit.edu koniec pliku (strumienia) danych oraz −1 w wy-# Thanks to Michael Brennan for the idea# August 1995 padku napotkania błędu (np. otwarcia pliku). Je- żeli po słowie getline występuje zmienna zfunction usage() { to wczytana linia jest dostępna jako wartość tej print "usage: awksed pat repl files..." > "con" zmiennej, w innym wypadku jest dostępna jako exit 1 wartość zmiennej $0. Przykładowo pętla:}BEGIN { while (getline < plik > 0) {...} # validate arguments Jest „tradycyjną” techniką umożliwiającą przejrze- if (ARGC < 3) { usage() } nie całego pliku . Poszczególne linie dostępne są RS = ARGV[1]; ORS = ARGV[2] w każdej iteracji pętli jako wartości zmiennej $0. # dont use arguments as files Podobnie wygląda czytanie danych z potoku. ARGV[1] = ARGV[2] = "" Przykładowo chcąc przekazać do AWK-a zawar-} tość bieżącego katalogu możemy się posłużyć następującą pętlą (dla system DOS):{ if (RT == ""){ printf "%s", $0 } while ("dir/b *.*" | getline > 0) {...} else { print } Pliki i potoki otwarte przez AWK-a są automatycz-} nie zamykane z chwilą zakończenia działania pro-Idea działania jest prosta: separatorem rekordów jest co gramu. Jeżeli jednak musimy przeglądać wielo-a separatorem rekordów na wyjściu naco . Problemem krotnie zawartość jakiegoś pliku w obrębie jed-jest jedynie sytuacja, w której ostatni rekord nie kończy się nego programu AWK-owego to za każdym razemnapisem pasującym do RS. Je eli plik nie kończy się napi- należy zamknąć czytany plik używając instrukcjisem pasującym do RS to zmienna RT będzie równa napi-sowi pustemu. Stąd, warunek if (RT=="")... gwaran- close, np.tuje wydrukowanie całej zawartości pliku wejściowego. close ( plik ); close("dir /b *.*") Drugi ciekawy fragment tego przykładu to przypisa-nie ARGV[1] = ARGV[2] = "". Chodzi o to, eby AWK nie przykład 10traktował napisów co i naco jako nazw plików wejścio- Poniższy program po uruchomieniu wyświetli listęwych. Dokładne wyjaśnienie znaczenia tej linijki znajduje wszystkich plików, których wielkość jest większa odsię w punkcie Argumenty wywołania programu, s. 24. SIZE.
  • 13. 22 GUST, Zeszyt 7 1996BEGIN { zawierającego ciąg oddzielonych odstępami liczb. Ka da flag = 1 liczba oznacza długość odpowiedniego pola w znakach. SIZE = 1000000 Je eli wartością zmiennej FIELDWIDTHS nie jest napis pu- while ("dir /s/a-d" | getline) { sty, pola wyznaczane są w oparciu o specyfikację podaną gsub(/./,""); w tej zmiennej, a nie w oparciu wartość separatora pól if ($NF ~/[0-90-9]:[0-90-9]/ && $(NF-2)> SIZE) (czyli zmienną FS). Przypisanie wartości zmiennej FS (np. {print $0; flag =0} FS=FS) przywraca standardowy sposób wyznaczania pól. } Zwróćmy uwagę, e GAWK nie dokonuje adnego sprawdzenia poprawności specyfikacji podanej w napisie if (flag) FIELDWIDTHS {print "NO FILES BIGGER THAN", SIZE; }} przykład 12 Następujący program wyświetli listę wszystkich plików,Uwagi: Ponieważ DOS wyświetla wielkość plików z krop- których wielkość jest większa od SIZE. Lista plików ge-kami „księgowymi” przed każdymi trzema cyframi, tj. na nerowana poleceniem dir ma zmienną liczbę pól w zale -przykład 200.124 pozbywamy się ich za pomocą funk- ności od tego czy nazwa pliku ma czy nie ma rozszerze-cji gsub. Instrukcja if najpierw testuje czy wczytana nie (pomijamy na razie nagłówek i katalogi). W przykła-linia zawiera ostatnie pole składające się z czterch cyfr dzie 10 liczyliśmy pola od końca. Posługując się zmiennąz dwukropkiem po pierwszej parze (czas ostatniej mo-dyfikacji pliku). Ta sztuczka pozwala „odcedzić” pola FIELDWIDTHS mo emy rozwiązać problem inaczej:nie zawierające informacji o plikach (nagłówek listy BEGIN {FIELDWIDTHS = "8 1 3 14 1 8 3 5";i statystykę zbiorczą). Następnie sprawdzany jest wa- BEGIN { SIZE = 1000000 }runek czy wielkość pola jest większa od SIZE. Polaliczymy od końca gdyż tylko wtedy możemy jedno- { gsub(/./,"",$0); }znacznie ustalić, która kolumna zawiera wielkość pliku(druga od końca). $0 !~ /<DIR>/ && $1 !~ /^ / && $4 > SIZE { printf "%s %s %dn", $1, $3, $4;przykład 11 }Poniższy funkcja pobiera bieżącą datę z komputera Program uruchamiamy w „egzotyczny”, jak na systemi udostępnia ją w trzyelementowej tablicy CDATE, której DOS, sposób (zakładając, e powy szy kod znajduje sięelement "year" zawiera rok, element "mon" – miesiąc w chksize.awk):a element "day" – dzień. dir | gawk -f chksize.awkfunction getdate(x,date) { "echo. | date" | getline x; gsub("-", " ", x); Instrukcje wyjścia – print/printf split(x, date, " "); CDATE["year"]= date[5]; Instrukcje print oraz printf służą do druko- CDATE["mon"]= date[6]; wania. Pierwsza z nich drukuje swoje argumenty CDATE["day"]= date[7]; zawsze według tego samego formatu, druga return;} umożliwia precyzyjniejsze sterowanie postacią wy-Uwagi: "echo. | date" z góry odpowiada DOS-owi na pisywanych danych. Dane mogą być drukowanejego durne pytanie Enter new date... (inaczej pro- na ekran, do pliku lub do potoku.gram będzie czekał na naciśnięcie enter). Argumenty printf. Składnia instrukcji printf jest niemalżex, i date nie służą do przekazywania wartości, ale douczynienia obu zmiennych lokalnymi (por. rozważania identyczna z odpowiednią funkcją języka C.na ten temat w punkcie: Funkcje) – funkcję wywołujemy Ogólna postać tej instrukcji jest następująca:po prostu getdate() 8 . printf format , arg1 , arg2 ,...Pola o ustalonej długości. Rekord mo e być tak e lubdzielony na pola o ustalonej długości. W tym celu zmien-nej wbudowanej FIELDWIDTHS nadajemy wartość napisu printf ( format , arg1 , arg2 ,...) Napis lub zmienna napisowa format określa spo-8: Zwracamy uwagę, że program jest „nieodporny” na sób przekształcania i formatowania argumentów.zmianę formatu daty, co w DOS-ie ma miejsce przy uak- Zawiera on dwa rodzaje obiektów: zwykłe znaki,tywnieniu innej strony kodowej. Bardziej inteligentna kopiowane po prostu przy drukowaniu oraz spe-wersja może rozpoznawać która liczba jest dniem, któramiesiącem a która rokiem po zawartości drugiej linii cyfikacje przekształceń z których każda określadrukowanej przez polecenie date, tj. tekstu: Enter sposób przekształcenia i wypisania kolejnego argu-new date (yy-mm-dd). mentu funkcji printf. Specyfikacja ta rozpoczyna
  • 14. 1996 GUST, Zeszyt 7 23się od znaku % a kończy znakiem określającym typ %-.3s Alibaba |Ali|konwersji. Pomiędzy tymi znakami możemy użyć %-9.3s Alibaba |Ali |ponadto następujących znaków modyfikujących: -, zawartość pola jest justowana do lewego print. Instrukcja print jest uproszczoną formą krańca pola; printf a jej działanie jest następujące: druko- ciąg-cyfr , określający minimalny rozmiar pola wane argumenty są oddzielane znakiem usta- (w znakach). Przekształcony argument będzie lonym jako wartość zmiennej wbudowanej OFS wpisany do pola o długości co najmniej równej (standardowo OFS=" " – argumenty odzielone są ciąg-cyfr . Jeżeli argument składa się z mniej- znakiem odstępu); na końcu listy jest drukowany szej liczby znaków, to będzie ono uzupełnione znak ustalonym jako wartość zmiennej wbudowa- do długości minimalnej znakami odstępu. Je- nej ORS (standardowo ORS="n" – każde kolejne żeli specyfikacja długości pola rozpoczyna print drukuje od nowego wiersza). Wszystkie ar- się cyfrą 0, to pole będzie wypełniane nie gumenty są drukowane w oparciu o tę samą specy- znaczącymi zerami; fikację, określoną poprzez wartość zmiennej OFMT . ciąg-cyfr , maksymalna szerokość pola (dla (standardowo OFMT="%.6g"). Stąd, uruchamiając napisu) lub liczba cyfr po kropce dziesiętnej. poniższy przykład:Oto lista znaków przekształceń i ich znaczenie: BEGIN {OFS=":";ORS="->"; print log(2), log(3); print log(5); Znaki konwersji }Znak Typ przekształcenia otrzymamy c znak 0.693147:1.09861->1.60944-> d liczba całkowita Uwagi: print to skrót od print $0 (a nie jak e liczba postaci [-]d.ddddddE[+-]dd f liczba postaci [-]ddd.dddddd można by się spodziewać print ORS). g e lub f, w zależności od tego które jest krótsze Drukowanie do plików. Zamiast na ekran (stan- przy czym nieznaczące zera nie są drukowane dardowe wyjście) instrukcje printf/print mogą o liczba ósemkowa bez znaku s napis przesłać dane do pliku. Służą do tego operatory > x liczba szestnastkowa bez znaku oraz >>, zaś instrukcja mają wówczas postać: printf format , arg1 ,... > plikJeżeli znak występujący po % nie jest znakiem prze- print arg1 ,... > plikkształcenia to jest on po prostu wypisany; zatem %%spowoduje wypisanie znaku %. lub printf format , arg1 ,... >> plik Poniższe zestawienie ilustruje działanie róż- print arg1 ,... >> pliknych specyfikacji. Aby można ocenić długości plik jest napisem lub zmienną typu napiso-pól otoczono je znakami |, zaś spacje oznaczono wego zawierającą legalną (z punktu widzeniaznakiem . systemu operacyjnego) nazwę pliku. Przykładowo program: Przykłady specyfikacji { printf "%sn", $0 > $1 }Specyfikacja Argument Wynik będzie działał doputy, dopóki wartość pierwszego%5d%% 33.33 | 33%| pola w pliku wejściowym zawiera napis mogący%c 33.33 |!|%d 33.33 |33| być legalną nazwą pliku (w systemie UNIX byłby%5d 33.33 | 33| problem jeżeli $1 zawierałoby dla którejś linii pliku%e 3.1415 |3.141500e+000| np. frazę Procter&Gamble).%f 3.1415 |3.141500| Uwagi: Instrukcja printf "%d %dn", $1, $2%8.3f 3.1415 | 3.141| > $3 spowoduje wydrukowanie $1 i $2 do%08.3f 3.1415 |0003.141|%s Alibaba |Alibaba| pliku określonego jako zawartość pola $3, a nie%9s Alibaba | Alibaba| $1 oraz wyniku porówania wartości drugiego%-9s Alibaba |Alibaba | i trzeciego pola. Jeżeli chcemy osiągnąć to drugie
  • 15. 24 GUST, Zeszyt 7 1996to powinniśmy napisać: printf "%d %dn", $1, system. Instrukcja system ma postać:($2 > $3) albo printf ("%d %dn", $1, $2 system( komenda )>$3). wykonuje komendę systemową przekazaną jej Operator > otwiera plik tylko raz (niszcząc jako wartość napisowego argumentu komenda .poprzednią zawartość); kolejne instrukcje printf Najczęściej funkcje printf/printf i operatorydodają tekst do tego pliku. Operator >> różni >, >> i | wystarczają do zrealizowania typowychsię od > tym, że przy otwarciu pliku poprzednia zadań bez potrzeby uciekania się do komendyzawartość nie jest niszczona. system.Drukowanie w potoku. Możliwe jest także dru-kowanie w potoku za pomocą instrukcji printf Argumenty wywołania programu(print) o postaci: Wartości argumentów wywołania programu są, printf format , arg1 ,... | program podobnie jak w wypadku języka C, przechowy- print arg1 ,... | program wane we wbudowanej zmiennej tablicowej ARGV. program jest napisem lub zmienną napisową Zmienna ARGC zaś zawiera liczbę argumentów.zawierającą nazwą programu-odbiorcy strumienia Przykładowo:danych drukowanych przez printf (print). gawk -f 1.awk test.txt v=1 bRozważmy prosty program drukujący z plikuwejściowego linie zawierające więcej niż 9 pól. Nic ARGC ma wartość 4, ARGV[0] ="gawk", ARGV[1]prostszego jak zapisać NF > 9{print }. Jednakże ="test.txt", ARGV[2] ="v=1", ARGV[3] ="b".gdy liczba linii spełniających ten warunek jest Jak widzimy argumenty zdefiniowane za po-duża to na ekranie zobaczymy tylko dwadzieścia mocą opcji -f nie są liczone (podobnie -v) aleparę ostatnich, a reszta mignie nam przed oczami. za to ARCV[0] jest równa nazwie programu,W systemie DOS możemy usunąć tę niedogodność który uruchomiliśmy (tu „gawk”). Poniższy pro-pisząc 9 : gram wypisuje wartość wszystkich argumentów wywołania: NF > 9 {print | "more"} BEGIN {for (i=0; i< ARGC; i++)close. Instrukcja close służy do zamknięcia {print ARGV[i]}otwartego za pomocą operatorów >, >> i |. Jej }ogólna postać jest następująca: Zmienne ARGC i ARGV mo na zmieniać wewnątrz pro- close( napis ) gramu. Po napotkaniu końca bie ącego pliku wejściowego AWK pobiera następny element tablicy ARGV jako nazwęgdzie napis jest identyczny z napisem plik lub następnego pliku wejściowego. Przykładowo: program , za pomocą których uprzednio otwarto BEGIN{ ARGV[1]="test.txt";plik/potok. Instrukcja ta jest niezbędna w sytuacji if(ARGC < 2) {ARGC = 2} }gdy np. najpierw piszemy do pliku a następnie spowoduje, e AWK, zawsze będzie przeszukiwał jakochcemy (w obrębie tego samego programu) czytać pierwszy plik „test.txt” bez względu na to jaki (i czyz niego dane. w ogóle) podamy w linii komend. Aby usunąć nazwę pliku z tablicy ARGV mo emy albofflush. Instrukcja fflush o postaci nadać odpowiedniemu elementowi tablicy wartość napisu fflush( napis ) pustego, albo posłu yć się poleceniem delete. Napisopró nia bufor związany z jakimś plikiem lub potokiem (po- „-” oznacza standardowe wejście. Tego typu manipula-przez napis , identyczny z napisem plik lub program cje z reguły umieszczamy wewnątrz wzorca BEGIN, por.za pomocą których uprzednio otwarto plik/potok). Do- przykład 9.puszczalne są tak e dwie następujące postacie instruk- Poniewa nie wiemy na ile omówione tutaj mo liwo-cji: fflush() oraz fflush(""). Pierwsza opró nia bu- ści manipulowania zmiennymi ARGV i ARGC są przenośnefor związany ze standardowym wyjściem, druga bufory dla innych implementacji AWK-a na wszelki wypadek ozna-związane z wszystkimi otwartymi w danej chwili pli- czyliśmy je jako rozszerzenia GAWK-a pismem pochyłym.kami/potokami. przykład 13 W przykładzie 10 wielkość pliku była zadeklarowana na9: Przykład trochę naciągany gdyż to samo można stałe co jest pewną niedogodnością, poniższa modyfi-osiągnąć pisząc w linii komend gawk "NF > 9 kacja pozbawiona jest już tej wady. Chcąc uzyskać listę{print }" | more. plików np. większych od 500kb, wystarczy teraz napisać
  • 16. 1996 GUST, Zeszyt 7 25gawk -f chkbig.awk 500 (gdzie chkbig.awk zawieraponiższy kod).BEGIN { flag = 1 if (ARGC > 0) {SIZE = ARGV[1] * 1000} else { SIZE = 1000000} # defaultdalej jak w przykładzie 10}Uruchamianie AWK-a. Do tej pory uruchamiali-śmy AWK-a pisząc: gawk -f prog.awk plik.we plik.we ...Jest to sposób stosowany najczęściej, ale nie je- Rys. Miejsce AWK w TEX-owym środowisku składudyny. Jeżeli program AWK-owy jest bardzo krótkimożna napisać po prostu 10 : Jeszcze wygodniejsze będzie przygotowanie odpowied- gawk " instrukcje " plik.we niego skryptu bat, np. chkbig.bat:np. @echo off if %1.==. goto STANDARD gawk "NF != 5{print $0}" plik.we gawk -vSIZE=%1000 -f chkbig.awkAWK można wywołać z kilkunastoma opcjami. Naj- goto ENDważniejsze z nich to -f, -F oraz -v. Dwie pierw- :STANDARDsze już omówiliśmy, ostatnia umożliwia nadanie gawk -vSIZE=500000 -f chkbig.awk :ENDzmiennej 11 wartości w momencie uruchomienia Żeby otrzymać listę plików większych od np. 600kbprogramu (z linii komend). Przykład 14 ilustruje wystarczy teraz napisać w linii komend:sposób wykorzystania opcji -v. chkbig 600Uwagi: Z czasem gdy dorobimy się biblioteki wła-snych funkcji AWK-owych, może powstać problem,jak w elegancki sposób dołączać ją do róż- Podsumowanienych plików, w taki sposób, jak umożliwia to W artykule przedstawiono opis standardu AWK,instrukcja input w TEX-u czy instrukcja #in- oraz rozszerzenia tego języka oferowane przez in-clude w C? Okazuje się, że opcja -f nie musi terpreter GAWK. Przykłady przedstawione w arty-wcale występowąć tylko raz: kule oraz kilkanaście innych nie zaprezentowa- gawk -f mylib.awk -f prog.awk plik.we nych z braku miejsca są dostępne w archiwumGdzie plik mylib.awk zawiera bibliotekę naszych GUST-u (ftp.GUST.org.pl). Tam też znaleźćfunkcji. Nie jest to rozwiązanie idealne, ale według można dystrybucję GAWK-a (zawiera [4]), oraz [2].wiedzy autorów, najlepsze z możliwych.przykład 14 BibliografiaPrzykład 10 można zmodyfikować w inny sposób niż tenzaprezentowany w przykładzie 13. Wystarczy, że przy [1] Aho A.V., Kernighan B.W., Weinberger P The .J.,uruchamianiu pliku chk_big.awk będzie nadawana AWK Programming Language, Addison-Wesleyodpowiednia wartość zmiennej SIZE (oczywiste zmiany 1988.w pliku chkbig.awk pozostawiamy czytelnikom), np: [2] Aho A.V., Kernighan B.W., Weinberger P .J., gawk -vSIZE=500000 -f chkbig.awk AWK – A Pattern Scanning and Processing Lan- guage, dostępny m.in. w ftp.GUST.org.pl10: W systemie UNIX, zamiast cudzysłowów ma- jako plik postscriptowy, 1978.szynowych używamy cudzysłowów pojedynczych, [3] Kernighan B.W., Ritchie D.M., Język C, WNTtj. gawk instrukcje plik.we . 1988.11: Ogólnie zmiennym, ponieważ możemy ją [4] Robbins A.D., A User’s Guide for GNU AWK,używać wielokrotnie. version 3.0, January 1996.
  • 17. 26 GUST, Zeszyt 7 1996SkorowidzHasła oznaczone gwiazdką oznaczają rozszerzenia standarduAWK-a, zaś oznaczone znakiem † funkcje zdefiniowane przezautorów. ARGC, 24 log, 16 *ARGIND, 14, 18 ARGV, 24 match, 14, 16 atan2, 16 †max, 20 *AWKPATH, 14 next, instrukcja, 18 BEGIN, 12 *nextfile, instrukcja, 18 break, instrukcja, 18 OFMT, 23 close, 21, 24 OFS, 23 continue, instrukcja, 18 ORS, 23 cos, 16 print, 23 delete, 19, 24 do, instrukcja, 18 rand, 16 dopełnienie return, 19 — listy, 13 RS, 11, 14, 20, 21 — zakresu, 13 RT, 21 DOS, 10, 11, 14, 20–22, 24 sin, 16 END, 12 split, 14, 16 *ENVIRON, 14 sprintf, 16 *ERRNO, 14 sqrt, 16 exit, instrukcja, 18 srand, 16 exp, 16 *strftime, 17 sub, 14, 16 *fflush, 24 SUBSEP, 19 *FIELDWIDTHS, 22 substr, 16 FILENAME, 14, 18 system, 24 FNR, 18 *systime, 17 for, instrukcja, 18 FS, 12, 14, 20 tablice funkcje — wielowymiarowe, 19 — rekurencyjne, 20 TEX, 10 *tolower, 17 *gensub, 14, 16 *toupper, 17 gsub, 14, 16 unix, 10, 11, 23, 25 if, instrukcja, 18 †upper, 17 index, 14, 16 int, 16 while, instrukcja, 18 ISO-8859-1, 14 zakres, 13 length, 16 zmienne lista, 13 — globalne, 20 lista-argumentów, 19 — lokalne, 19 Bogusław Lichoński ekosg@univ.gda.pl Tomasz Przechlewski ekotp@univ.gda.pl

×