SlideShare ist ein Scribd-Unternehmen logo
1 von 17
Downloaden Sie, um offline zu lesen
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
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 linijka
w pliku wejściowym symbolizowana przez $0 jest          Istnieje wiele interpreterów AWK-a; w systemach
napisem 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: GAWK
par „ wzorzec { akcja }”. Dla każdej linii pliku        – firmowany przez Free Software Foundation czy
wejś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 oraz
stawowych 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 opis
z 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 oznaczony
sposób:                                                 w tekście za pomocą pisma pochyłego.
                                                             PRZEDSTAWIONE PRZYKŁADY SĄ PRZY-
  awk -f program       plik1   plik2 ...
                                                        GOTOWANE DO WYKONYWANIA W SYSTEMIE
W 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ściowego
tach 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 separatorem
miejsca – wszystko powinno być jasne.                   jest znak końca linii.
12                                            GUST, Zeszyt 7                                           1996

     Rekordy podzielone są na pola, które roz-          Wzorce BEGIN i END nie mogą być częścią wzorca
dzielone są separatorami pól FS. Standardowo            złożonego. Podobnie częścią wzorca złożonego nie może
separatorem pól jest znak spacji lub tabulacji.         być wzorzec z przecinkiem.

  RS i FS są zmiennymi, a więc można im
nadać 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 mu
separatorami 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. Podobnie
odwoł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 BEGIN
przechowywuje 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 na
Wzorce
                                                        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 AWK
akcje. W ogólnym wypadku wzorzec może być               dzieli linie czytanego pliku na pola. Wbudowana
kombinacją wyrażeń logicznych i wyrażeń regu-           zmienna FS definiuje jaki znak jest separatorem
larnych. 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 nadana
o nazwie BEGIN i END. Oto ogólna specyfikacja            wartość równa spacji (FS=" "). Przy uruchomieniu
wzorcó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 akcja
wego.                                                   jest wykonywana za każdym razem gdy takie
END{ 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 /. Podstawowe
wyraż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żenia
pliku 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żenia
tanego przez AWK pliku zawiera ciąg znaków pasujący
do 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 linii
zawierają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 do
bądź wyrażenie-regularne .                              wyrażenia regularnego r.
1996                                          GUST, Zeszyt 7                                               13

Wzorzec 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 znak
linii pliku wejściowego jeżeli wartością wyraże-        ^            początek napisu
nia jest prawda (czyli jest niezerowa lub niepusta).    $            koniec napisu
Przykł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-z
Wzorzec 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 r
do 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 regularnego
gularnych, które stanowią o sile tego języka. Nie       pasuje jeden dowolny znak z listy. Zakres znaków
bę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 interpretowane
i ł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/zakres
operacyjnemu, w którym zawarty był znak *; na           z poprzedzającym znakiem ^ (bezpośrednio po
przykład:                                               otwierającym nawiasie [). Przykładowo specyfi-
  > emacs *.tex                                         kacja [^0-9] oznacza jeden dowolny znak ale
Jeśli nie zdarzyło Ci się wydać takiego polecenia,      nie cyfrę; [^A-ZĄĆĘŁŃÓŚŹ ] dowolny znak nie
to 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ócz
edytować 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 dowolne
niem 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 (znak
owane z następujących elementów: „normalnych            cofnięcia, backspace), f (znak końca strony, form
znakó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 regularne
Wyraż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ócz
znakami .tex.                                           składających się ze spacji, znaków tabulacji i pustych;
14                                              GUST, Zeszyt 7                                             1996

  /[+-]?[0-9]+[.]?[0-9]*/ pasuje do liczby rze-          NR             liczba przeczytanych rekordów
czywistej 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. 23
nych 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ów
Wyrażenia                                                RT             napis pasujący do wyra enia RS, por. 21
Podstawą składni wyrażeń AWK-a jest popularna            RSTART         por. opis funkcji match, s. 16
                                                         SUBSEP         separator indeksów tablic, por. s. 19
składnia wyrażeń języka C. Składnia ta została
w 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;gslibpsfonts
wartości zmiennopozycyjne, przy czym ich do-                AWKPATH – nazwa zmiennej środowiskowej zawierają-
                                                         cej ście ki dostępu do katalogów zawierających programy
kładność zależna jest od implementacji. Zmienne
                                                         AWK-owe (czyli pliki *.awk) Je eli zmiennej AWKPATH nie
napisowe 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 lub
konwersja. 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, wtedy
logicznych. Fałsz odpowiada liczbie 0 i napisowi         operatory ~, !~ oraz funkcje gensub, gsub, index,
                                                         match, split oraz sub nie rozró niają du ych i małych
pustemu "", zaś prawda odpowiada wszystkim
                                                         liter. Dotyczy to tak e wartości zmiennych wbudowanych
innym 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 tablicy
omawiania tych aspektów AWK-a, których dotyczą.          ARGV znajduje się nazwa przeglądanego pliku. Zawsze jest
Oto 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 arytmetyczne
ARGIND        index w ARGV odpowiadający                 są naszym zdaniem łatwe i intuicyjne:
              bie ącemu plikowi
ENVIRON       tablica zmiennych środowiskowych                          Operatory arytmetyczne
ERRNO         napis z systemowym opisem błędu
FIELDWIDTHS   specyfikacja długości pól, por. s. 22       Postać wyrażenia              Opis znaczenia
FILENAME      nazwa bieżącego pliku wejściowego          *                             iloczyn
FNR           numer bieżącego rekordu                    +                             suma
              w bieżącym pliku                           -                             różnica
FS            separator pól                              /                             iloraz
IGNORECASE    przełącznik rozró niania wysokości liter   %                             modulo
NF            liczba pól w bieżącym rekordzie            ^                             potęga
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 3
sowe można łączyć (konkatenować) przy po-            Zaimplementujmy funkcję, zwracającą 1 jeżeli rok jest
mocy „niewidocznego” operatora – po prostu           przestępny, lub 0 dla lat nieprzestępnych. Algorytm
należ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 dla
Operatory porównywania i operatory logiczne.         testowania funkcji. Jeżeli powyższy kod umieścimy
Zapis i działanie operatorów w AWK-u w wypadku       np. w pliku lyear.awk to pisząc gawk -f lyear.awk
zmiennych typu liczbowego jest identyczny jak        otrzymamy na ekranie:
w języku C. Nowością AWK-a jest to, że mogą być        100
takż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ę przecinkiem
Operator             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 x
giego 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 do
pewnego 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ń.
16                                                GUST, Zeszyt 7                                               1996

Oto 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: AlibaBAba
cos(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 napisie
exp(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 jest
nie 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 tylko
spowoduje nadanie zmiennej randint wartości                 z dwoma parametrami to znakiem separującym jest
                                                            znak określony wartością zmiennej FS, czyli separator
z 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 dokonanych
gsub( 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 p
tylko 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ładowo
równoważne gsub( r , s ,$0)).                               wykonanie instrukcji
gensub( 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 enie
regularne r w oparciu o napis s , w napisie t (je eli
nie 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, zamiast
nającym się od "g" (lub "G") to wymieniane są wszystkie     niezmienionego napisu t , liczba 5.9976e-315. Autorzy
napisy pasujące do r . Funkcja gensub umo liwia wsta-       nie natknęli się na inne błędy, i w związku z tym wydaje
wienie 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 : tmp
do tekstu zwracanego przez funkcję. W efekcie mo liwe są    }
1996                                             GUST, Zeszyt 7                                                 17

tolower( 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 newstring
Zwraca napis, w którym małe litery zostały zamienione na     }
du e. Z „polskiego” punktu widzenia ma tę samą wadę co
tolower.                                                     BEGIN{ LOWER = "abcdefghijklmnopqrs
                                                              tuvwxyząćęłńóśź ";
                                                              UPPER = "ABCDEFGHIJKLMNO
przykł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 pory
brakował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 czasu
przedza co , zaś fraza aft następuje po co i także jest
jednoznakowa. 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 sekund
na 1992–1993.                                              od 1 Stycznia 1970 r.
                                                             strftime( format , czas )
przykład 5 (GAWK3.0)                                       Zwraca napis zawierający czas (liczba w takim samym
Poni 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 konwersji
Poniższa funkcja jest odpowiednikiem funkcji toup-
                                                           (por. [4], s. 149–151), ograniczymy się do najczęściej
per; ma tę zaletę, że „rozpoznaje” polskie znaki. Ła-
                                                           stosowanych:
two też daje się modyfikować dla różnych wariantów
kodowania 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)
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, do
Instrukcje sterujące                                     next
AWK pozwala nam grupować instrukcje, podejmo-            rozpoczęcie następnej iteracji głównej pętli wejściowej 7
wać decyzje (konstrukcja if-else) oraz tworzyć           exit wyrażenie
pętle (instrukcje for, while). Składnia tych             sterowanie jest przekazywane bezpośrednio do akcji
                                                         END. Jeśli komendy exit użyto w akcji END, program
instrukcji 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-
                                                         nextfile
jące. Na liście instrukcje separowane są końcami         zakończenie przeglądania bie ącego pliku i przejście do
linii lub średnikami. Znaki końca linii mogą poja-       przeglądania następnego z podanych w linii komend, lub
wić 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 ) instrukcja
jeś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 instrukcja2
Wykonaj 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 jest
while ( w ) instrukcja
                                                         równy zero lub równy napisowi pustemu. Indeksy
jeśli wyrażenie w jest prawdziwe, wykonaj instrukcję     nie są liczbami ale napisami. Użycie w kontekście
i 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 tablicy
do 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 pliku
prawdziwe i powtórz                                      wejściowego.
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, do
wia się nowy wyraz, AWK tworzy nowy element           których możemy się odwoływać za pomocą par
tablicy 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 SUBSEP
zwię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 jest
wartości indeksów (wyrazów tekstu). Do tego celu      przecinek ale znak "034". Sposób testowania czy
sł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ądania
tablicy nie jest ustalona i jest zależna od kon-      Uwagi: Elementy tablic nie mogą być tablicami.
kretnej implementacji AWK-a. Działanie pętli jest
nieokreślone jeżeli wewnątrz pętli zostaną dodane     Funkcje
kolejne 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łania
jest 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ą lokalne
wystą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 funkcji
przykładowo delete ls["TeX"] usuwa z tablicy
                                                      (tzw. wartość zwracana przez funkcję). Wyrażenie
ls element odpowiadający indeksowi "TeX".
                                                      jest opcjonalne – jeżeli go nie ma, instrukcja
Tablice 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 nie
tablic jednowymiarowych. Z punktu widzenia            ma return to po wykonaniu ostatniej instrukcji
uż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
20                                            GUST, Zeszyt 7                                           1996

to 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 sytuacji
wyrażeniu, a także wewnątrz innych funkcji;             poszczególne pola są rozdzielone odstępami lub
dozwolona jest także rekursja (por. przykład 7).        znakami tabulacji. Sposób rozdzielania pól można
Przy 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 to
argumentó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ące
zmiennymi 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 pola
kąś 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ą FS
one wykorzystywane do przekazywania wartości,           jest pojedynczy znak (inny od odstępu) to ten znak
lecz 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ć nadana
nej 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ższego
wartości zerowe.                                        wzorca BEGIN moglibyśmy napisać w linii komend
przykład 7                                              (system DOS):
Następująca funkcja rekurencyjna odwraca napis poczy-     gawk -F[,;:] -f prog.awk plik.we
nają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żemy
Dla wypróbowania dopiszmy następujący prosty pro-
                                                        zmienić sposób w jaki AWK wyróżnia poszczególne
gram:
                                                        rekordy, nadając odpowiednią wartość zmien-
BEGIN {print rev("Vrooom",length("Vrooom"))}
                                                        nej RS. W opisie [1] separatorem rekordu może
Zakł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 naturalnym
Wejś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ów
W takim kontekście, zgodnie z tym co już napisano           print;
we wstępie, AWK czyta plik plik.we linia po linii.        }
1996                                                 GUST, Zeszyt 7                                               21

Wadą 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                                getline
rekordu, podobnie jak w wypadku gdy separatorem jest            Postać instrukcji           Inicjalizowane zmienne
pojedynczy znak.                                                getline                     $0, NF, NR, FNR
     Je eli RS jest wyra eniem regularnym wtedy zmienna         getline z                    z , NR, FNR
RT przechowuje dla bie ącego rekordu, napis będący jego         getline < plik              $0, NF
separatorem od rekordu następnego.                              getline z < plik             z
                                                                 program | getline          $0, NF
przykład 9 (edytor potokowy)                                     program | getline z         z
Nastę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órego
dalej. 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ła
bę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 z
function 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.
    # don't 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 razem
napisem pasującym do RS. Je eli plik nie kończy się napi-
                                                                należy zamknąć czytany plik używając instrukcji
sem 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 10
traktował 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 od
się w punkcie Argumenty wywołania programu, s. 24.              SIZE.
22                                               GUST, Zeszyt 7                                                1996

BEGIN {                                                     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. Pola
liczymy 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 system
i 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.awk
function 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ć drukowane
jego 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że
x, i date nie służą do przekazywania wartości, ale do
uczynienia 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            lub
dzielony 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óra
miesiącem a która rokiem po zawartości drugiej linii
                                                            cyfikacje przekształceń z których każda określa
drukowanej 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
1996                                            GUST, Zeszyt 7                                             23

się 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 ,... > plik
Jeżeli znak występujący po % nie jest znakiem prze-
                                                            print arg1 ,... > plik
kształ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 ,... >> plik
nych 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 widzenia
znakiem .                                                 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
24                                                 GUST, Zeszyt 7                                             1996

to 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 operatory
dodają tekst do tego pliku. Operator >> różni
                                                             >, >> i | wystarczają do zrealizowania typowych
się od > tym, że przy otwarciu pliku poprzednia
                                                             zadań bez potrzeby uciekania się do komendy
zawartość 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 b
Rozważmy prosty program drukujący z pliku
wejś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) ale
parę 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ł jako
chcemy (w obrębie tego samego programu) czytać               pierwszy plik „test.txt” bez względu na to jaki (i czy
z niego dane.                                                w ogóle) podamy w linii komend.
                                                                   Aby usunąć nazwę pliku z tablicy ARGV mo emy albo
fflush. Instrukcja fflush o postaci                            nadać odpowiedniemu elementowi tablicy wartość napisu
     fflush( napis )                                         pustego, albo posłu yć się poleceniem delete. Napis
opró 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śne
for 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 na
9: 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ć
1996                                                 GUST,   Zeszyt 7                                           25

gawk -f chkbig.awk 500 (gdzie chkbig.awk zawiera
poniższy kod).
BEGIN {
 flag = 1
 if (ARGC > 0) {SIZE = ARGV[1] * 1000}
 else { SIZE = 1000000} # default

dalej 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ładu
dyny. Jeżeli program AWK-owy jest bardzo krótki
moż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.awk
AWK  można wywołać z kilkunastoma opcjami. Naj-                    goto END
ważniejsze z nich to -f, -F oraz -v. Dwie pierw-                  :STANDARD
sze już omówiliśmy, ostatnia umożliwia nadanie                     gawk -vSIZE=500000 -f chkbig.awk
                                                                  :END
zmiennej 11 wartości w momencie uruchomienia
                                                                Żeby otrzymać listę plików większych od np. 600kb
programu (z linii komend). Przykład 14 ilustruje
                                                                wystarczy teraz napisać w linii komend:
sposób wykorzystania opcji -v.
                                                                  chkbig 600
Uwagi: 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óż-                      Podsumowanie
nych 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 archiwum
Gdzie 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                                                     Bibliografia
Przykład 10 można zmodyfikować w inny sposób niż ten
zaprezentowany 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-Wesley
odpowiednia 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.pl
10: 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, WNT
tj. 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.
26                                                         GUST, Zeszyt 7   1996

Skorowidz
Hasła oznaczone gwiazdką oznaczają rozszerzenia standardu
AWK-a, zaś oznaczone znakiem † funkcje zdefiniowane przez
autoró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

Weitere ähnliche Inhalte

Andere mochten auch (10)

Tundra animals
Tundra animals Tundra animals
Tundra animals
 
Band 6
Band 6Band 6
Band 6
 
Band 1
Band 1Band 1
Band 1
 
Dr. amadei 39_s_speech
Dr. amadei 39_s_speechDr. amadei 39_s_speech
Dr. amadei 39_s_speech
 
The Insider's Guide to Networking at an Event
The Insider's Guide to Networking at an EventThe Insider's Guide to Networking at an Event
The Insider's Guide to Networking at an Event
 
Presentasi isbd
Presentasi isbdPresentasi isbd
Presentasi isbd
 
Makalah isbd
Makalah isbdMakalah isbd
Makalah isbd
 
Rpt mt year 4
Rpt mt year 4Rpt mt year 4
Rpt mt year 4
 
An Introduction to Care About You
An Introduction to Care About YouAn Introduction to Care About You
An Introduction to Care About You
 
Deception: How the Media Strengthens Women Stereotypes
Deception: How the Media Strengthens Women StereotypesDeception: How the Media Strengthens Women Stereotypes
Deception: How the Media Strengthens Women Stereotypes
 

Awk

  • 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 linijka w pliku wejściowym symbolizowana przez $0 jest Istnieje wiele interpreterów AWK-a; w systemach napisem 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: GAWK par „ wzorzec { akcja }”. Dla każdej linii pliku – firmowany przez Free Software Foundation czy wejś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 oraz stawowych 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 opis z 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 oznaczony sposób: w tekście za pomocą pisma pochyłego. PRZEDSTAWIONE PRZYKŁADY SĄ PRZY- awk -f program plik1 plik2 ... GOTOWANE DO WYKONYWANIA W SYSTEMIE W 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ściowego tach 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 separatorem miejsca – 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ą wzorca dzielone są separatorami pól FS. Standardowo złożonego. Podobnie częścią wzorca złożonego nie może separatorem pól jest znak spacji lub tabulacji. być wzorzec z przecinkiem. RS i FS są zmiennymi, a więc można im nadać 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 mu separatorami 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. Podobnie odwoł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 BEGIN przechowywuje 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 na Wzorce 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 AWK akcje. W ogólnym wypadku wzorzec może być dzieli linie czytanego pliku na pola. Wbudowana kombinacją wyrażeń logicznych i wyrażeń regu- zmienna FS definiuje jaki znak jest separatorem larnych. 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 nadana o nazwie BEGIN i END. Oto ogólna specyfikacja wartość równa spacji (FS=" "). Przy uruchomieniu wzorcó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 akcja wego. jest wykonywana za każdym razem gdy takie END{ 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 /. Podstawowe wyraż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żenia pliku 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żenia tanego przez AWK pliku zawiera ciąg znaków pasujący do 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 linii zawierają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 do bądź wyrażenie-regularne . wyrażenia regularnego r.
  • 4. 1996 GUST, Zeszyt 7 13 Wzorzec 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 znak linii pliku wejściowego jeżeli wartością wyraże- ^ początek napisu nia jest prawda (czyli jest niezerowa lub niepusta). $ koniec napisu Przykł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-z Wzorzec 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 r do 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 regularnego gularnych, które stanowią o sile tego języka. Nie pasuje jeden dowolny znak z listy. Zakres znaków bę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 interpretowane i ł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/zakres operacyjnemu, w którym zawarty był znak *; na z poprzedzającym znakiem ^ (bezpośrednio po przykład: otwierającym nawiasie [). Przykładowo specyfi- > emacs *.tex kacja [^0-9] oznacza jeden dowolny znak ale Jeśli nie zdarzyło Ci się wydać takiego polecenia, nie cyfrę; [^A-ZĄĆĘŁŃÓŚŹ ] dowolny znak nie to 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ócz edytować 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 dowolne niem 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 (znak owane z następujących elementów: „normalnych cofnięcia, backspace), f (znak końca strony, form znakó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 regularne Wyraż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ócz znakami .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ów czywistej 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. 23 nych 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ów Wyrażenia RT napis pasujący do wyra enia RS, por. 21 Podstawą składni wyrażeń AWK-a jest popularna RSTART por. opis funkcji match, s. 16 SUBSEP separator indeksów tablic, por. s. 19 składnia wyrażeń języka C. Składnia ta została w 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;gslibpsfonts wartości zmiennopozycyjne, przy czym ich do- AWKPATH – nazwa zmiennej środowiskowej zawierają- cej ście ki dostępu do katalogów zawierających programy kładność zależna jest od implementacji. Zmienne AWK-owe (czyli pliki *.awk) Je eli zmiennej AWKPATH nie napisowe 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 lub konwersja. 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, wtedy logicznych. Fałsz odpowiada liczbie 0 i napisowi operatory ~, !~ oraz funkcje gensub, gsub, index, match, split oraz sub nie rozró niają du ych i małych pustemu "", zaś prawda odpowiada wszystkim liter. Dotyczy to tak e wartości zmiennych wbudowanych innym 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 tablicy omawiania tych aspektów AWK-a, których dotyczą. ARGV znajduje się nazwa przeglądanego pliku. Zawsze jest Oto 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 arytmetyczne ARGIND index w ARGV odpowiadający są naszym zdaniem łatwe i intuicyjne: bie ącemu plikowi ENVIRON tablica zmiennych środowiskowych Operatory arytmetyczne ERRNO napis z systemowym opisem błędu FIELDWIDTHS specyfikacja długości pól, por. s. 22 Postać wyrażenia Opis znaczenia FILENAME nazwa bieżącego pliku wejściowego * iloczyn FNR numer bieżącego rekordu + suma w bieżącym pliku - różnica FS separator pól / iloraz IGNORECASE przełącznik rozró niania wysokości liter % modulo NF 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 3 sowe można łączyć (konkatenować) przy po- Zaimplementujmy funkcję, zwracającą 1 jeżeli rok jest mocy „niewidocznego” operatora – po prostu przestępny, lub 0 dla lat nieprzestępnych. Algorytm należ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 dla Operatory porównywania i operatory logiczne. testowania funkcji. Jeżeli powyższy kod umieścimy Zapis i działanie operatorów w AWK-u w wypadku np. w pliku lyear.awk to pisząc gawk -f lyear.awk zmiennych typu liczbowego jest identyczny jak otrzymamy na ekranie: w języku C. Nowością AWK-a jest to, że mogą być 100 takż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ę przecinkiem Operator 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 x giego 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 do pewnego 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 1996 Oto 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: AlibaBAba cos(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 napisie exp(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 jest nie 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 tylko spowoduje nadanie zmiennej randint wartości z dwoma parametrami to znakiem separującym jest znak określony wartością zmiennej FS, czyli separator z 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 dokonanych gsub( 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 p tylko 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ładowo równoważne gsub( r , s ,$0)). wykonanie instrukcji gensub( 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 enie regularne r w oparciu o napis s , w napisie t (je eli nie 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, zamiast nającym się od "g" (lub "G") to wymieniane są wszystkie niezmienionego napisu t , liczba 5.9976e-315. Autorzy napisy pasujące do r . Funkcja gensub umo liwia wsta- nie natknęli się na inne błędy, i w związku z tym wydaje wienie 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 : tmp do tekstu zwracanego przez funkcję. W efekcie mo liwe są }
  • 8. 1996 GUST, Zeszyt 7 17 tolower( 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 newstring Zwraca napis, w którym małe litery zostały zamienione na } du e. Z „polskiego” punktu widzenia ma tę samą wadę co tolower. BEGIN{ LOWER = "abcdefghijklmnopqrs tuvwxyząćęłńóśź "; UPPER = "ABCDEFGHIJKLMNO przykł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 pory brakował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 czasu przedza co , zaś fraza aft następuje po co i także jest jednoznakowa. 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 sekund na 1992–1993. od 1 Stycznia 1970 r. strftime( format , czas ) przykład 5 (GAWK3.0) Zwraca napis zawierający czas (liczba w takim samym Poni 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 konwersji Poniższa funkcja jest odpowiednikiem funkcji toup- (por. [4], s. 149–151), ograniczymy się do najczęściej per; ma tę zaletę, że „rozpoznaje” polskie znaki. Ła- stosowanych: two też daje się modyfikować dla różnych wariantów kodowania 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, do Instrukcje sterujące next AWK pozwala nam grupować instrukcje, podejmo- rozpoczęcie następnej iteracji głównej pętli wejściowej 7 wać decyzje (konstrukcja if-else) oraz tworzyć exit wyrażenie pętle (instrukcje for, while). Składnia tych sterowanie jest przekazywane bezpośrednio do akcji END. Jeśli komendy exit użyto w akcji END, program instrukcji 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- nextfile jące. Na liście instrukcje separowane są końcami zakończenie przeglądania bie ącego pliku i przejście do linii lub średnikami. Znaki końca linii mogą poja- przeglądania następnego z podanych w linii komend, lub wić 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 ) instrukcja jeś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 instrukcja2 Wykonaj 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 jest while ( w ) instrukcja równy zero lub równy napisowi pustemu. Indeksy jeśli wyrażenie w jest prawdziwe, wykonaj instrukcję nie są liczbami ale napisami. Użycie w kontekście i 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 tablicy do 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 pliku prawdziwe 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, do wia się nowy wyraz, AWK tworzy nowy element których możemy się odwoływać za pomocą par tablicy 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 SUBSEP zwię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 jest wartości indeksów (wyrazów tekstu). Do tego celu przecinek ale znak "034". Sposób testowania czy sł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ądania tablicy nie jest ustalona i jest zależna od kon- Uwagi: Elementy tablic nie mogą być tablicami. kretnej implementacji AWK-a. Działanie pętli jest nieokreślone jeżeli wewnątrz pętli zostaną dodane Funkcje kolejne 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łania jest 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ą lokalne wystą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 funkcji przykładowo delete ls["TeX"] usuwa z tablicy (tzw. wartość zwracana przez funkcję). Wyrażenie ls element odpowiadający indeksowi "TeX". jest opcjonalne – jeżeli go nie ma, instrukcja Tablice 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 nie tablic jednowymiarowych. Z punktu widzenia ma return to po wykonaniu ostatniej instrukcji uż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 1996 to 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 sytuacji wyrażeniu, a także wewnątrz innych funkcji; poszczególne pola są rozdzielone odstępami lub dozwolona jest także rekursja (por. przykład 7). znakami tabulacji. Sposób rozdzielania pól można Przy 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 to argumentó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ące zmiennymi 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 pola kąś 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ą FS one wykorzystywane do przekazywania wartości, jest pojedynczy znak (inny od odstępu) to ten znak lecz 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ć nadana nej 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ższego wartości zerowe. wzorca BEGIN moglibyśmy napisać w linii komend przykład 7 (system DOS): Następująca funkcja rekurencyjna odwraca napis poczy- gawk -F[,;:] -f prog.awk plik.we nają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żemy Dla wypróbowania dopiszmy następujący prosty pro- zmienić sposób w jaki AWK wyróżnia poszczególne gram: rekordy, nadając odpowiednią wartość zmien- BEGIN {print rev("Vrooom",length("Vrooom"))} nej RS. W opisie [1] separatorem rekordu może Zakł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 naturalnym Wejś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ów W 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 21 Wadą 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 getline rekordu, podobnie jak w wypadku gdy separatorem jest Postać instrukcji Inicjalizowane zmienne pojedynczy znak. getline $0, NF, NR, FNR Je eli RS jest wyra eniem regularnym wtedy zmienna getline z z , NR, FNR RT przechowuje dla bie ącego rekordu, napis będący jego getline < plik $0, NF separatorem od rekordu następnego. getline z < plik z program | getline $0, NF przykład 9 (edytor potokowy) program | getline z z Nastę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órego dalej. 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ła bę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 z function 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. # don't 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 razem napisem pasującym do RS. Je eli plik nie kończy się napi- należy zamknąć czytany plik używając instrukcji sem 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 10 traktował 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 od się w punkcie Argumenty wywołania programu, s. 24. SIZE.
  • 13. 22 GUST, Zeszyt 7 1996 BEGIN { 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. Pola liczymy 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 system i 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.awk function 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ć drukowane jego 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że x, i date nie służą do przekazywania wartości, ale do uczynienia 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 lub dzielony 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óra miesiącem a która rokiem po zawartości drugiej linii cyfikacje przekształceń z których każda określa drukowanej 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 23 się 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 ,... > plik Jeżeli znak występujący po % nie jest znakiem prze- print arg1 ,... > plik kształ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 ,... >> plik nych 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 widzenia znakiem . 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 1996 to 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 operatory dodają tekst do tego pliku. Operator >> różni >, >> i | wystarczają do zrealizowania typowych się od > tym, że przy otwarciu pliku poprzednia zadań bez potrzeby uciekania się do komendy zawartość 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 b Rozważmy prosty program drukujący z pliku wejś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) ale parę 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ł jako chcemy (w obrębie tego samego programu) czytać pierwszy plik „test.txt” bez względu na to jaki (i czy z niego dane. w ogóle) podamy w linii komend. Aby usunąć nazwę pliku z tablicy ARGV mo emy albo fflush. Instrukcja fflush o postaci nadać odpowiedniemu elementowi tablicy wartość napisu fflush( napis ) pustego, albo posłu yć się poleceniem delete. Napis opró 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śne for 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 na 9: 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 25 gawk -f chkbig.awk 500 (gdzie chkbig.awk zawiera poniższy kod). BEGIN { flag = 1 if (ARGC > 0) {SIZE = ARGV[1] * 1000} else { SIZE = 1000000} # default dalej 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ładu dyny. Jeżeli program AWK-owy jest bardzo krótki moż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.awk AWK można wywołać z kilkunastoma opcjami. Naj- goto END ważniejsze z nich to -f, -F oraz -v. Dwie pierw- :STANDARD sze już omówiliśmy, ostatnia umożliwia nadanie gawk -vSIZE=500000 -f chkbig.awk :END zmiennej 11 wartości w momencie uruchomienia Żeby otrzymać listę plików większych od np. 600kb programu (z linii komend). Przykład 14 ilustruje wystarczy teraz napisać w linii komend: sposób wykorzystania opcji -v. chkbig 600 Uwagi: 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óż- Podsumowanie nych 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 archiwum Gdzie 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 Bibliografia Przykład 10 można zmodyfikować w inny sposób niż ten zaprezentowany 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-Wesley odpowiednia 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.pl 10: 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, WNT tj. 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 1996 Skorowidz Hasła oznaczone gwiazdką oznaczają rozszerzenia standardu AWK-a, zaś oznaczone znakiem † funkcje zdefiniowane przez autoró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