Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00509 008265 11004441 na godz. na dobę w sumie
Programowanie skryptów powłoki - książka
Programowanie skryptów powłoki - książka
Autor: Liczba stron: 560
Wydawca: Helion Język publikacji: polski
ISBN: 83-246-0131-7 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> systemy operacyjne >> unix
Porównaj ceny (książka, ebook, audiobook).

Efektywne wykorzystanie potencjału systemów uniksowych

W dobie graficznych narzędzi programistycznych często pomijamy tradycyjne metody rozwiązywania przeróżnych zadań związanych z działaniem systemu operacyjnego. Skrypty powłoki, niegdyś podstawowe narzędzie administratorów i programistów systemów uniksowych, dziś są zdecydowanie mniej popularne. Skrypty powłoki są przydatne zarówno administratorom systemu, jak i szeregowym użytkownikom, ponieważ są jednym z najlepszych sposobów na zaprzęgnięcie do pracy setek narzędzi, w jakie wyposażony jest Unix. Z narzędzi tych w języku programowania powłoki łatwo stworzyć rozwiązanie niemal dowolnego zadania związanego z przetwarzaniem danych.

Książka 'Programowanie skryptów powłoki' to kompendium wiedzy dotyczącej tej nieco już zapomnianej techniki. Przedstawia nie tylko język programowania powłoki, ale także narzędzia systemu Unix. Dostarcza informacji o tym, do jakich zadań się nadają, jak je wywoływać i jak łączyć je z innymi programami, konstruując z nich mechanizm przetwarzania danych. W książce opisano nie tylko sposoby pisania użytecznych skryptów powłoki, ale również metody dostosowywania powłoki do własnych potrzeb oraz przenoszenia skryptów pomiędzy różnymi wariantami Uniksa i różnymi implementacjami powłoki.

Książka 'Programowanie skryptów powłoki' zawiera wszystkie informacje niezbędne do mistrzowskiego opanowania narzędzi oferowanych przez systemy uniksowe.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREŒCI SPIS TREŒCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOŒCIACH O NOWOŒCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl Programowanie skryptów pow³oki Autorzy: Arnold Robbins, Nelson H. F. Beebe T³umaczenie: Przemys³aw Szeremiota ISBN: 83-246-0131-7 Tytu³ orygina³u: Classic Shell Scripting Format: B5, stron: 560 Efektywne wykorzystanie potencja³u systemów uniksowych • Automatyzacja zadañ • Przeszukiwanie plików i katalogów • Przenoszenie skryptów pomiêdzy systemami W dobie graficznych narzêdzi programistycznych czêsto pomijamy tradycyjne metody rozwi¹zywania przeró¿nych zadañ zwi¹zanych z dzia³aniem systemu operacyjnego. Skrypty pow³oki, niegdyœ podstawowe narzêdzie administratorów i programistów systemów uniksowych, dziœ s¹ zdecydowanie mniej popularne. Skrypty pow³oki s¹ przydatne zarówno administratorom systemu, jak i szeregowym u¿ytkownikom, poniewa¿ s¹ jednym z najlepszych sposobów na zaprzêgniêcie do pracy setek narzêdzi, w jakie wyposa¿ony jest Unix. Z narzêdzi tych w jêzyku programowania pow³oki ³atwo stworzyæ rozwi¹zanie niemal dowolnego zadania zwi¹zanego z przetwarzaniem danych. Ksi¹¿ka „Programowanie skryptów pow³oki” to kompendium wiedzy dotycz¹cej tej nieco ju¿ zapomnianej techniki. Przedstawia nie tylko jêzyk programowania pow³oki,ale tak¿e narzêdzia systemu Unix. Dostarcza informacji o tym, do jakich zadañ siê nadaj¹, jak je wywo³ywaæ i jak ³¹czyæ je z innymi programami, konstruuj¹c z nich mechanizm przetwarzania danych. W ksi¹¿ce opisano nie tylko sposoby pisania u¿ytecznych skryptów pow³oki, ale równie¿ metody dostosowywania pow³oki do w³asnych potrzeb oraz przenoszenia skryptów pomiêdzy ró¿nymi wariantami Uniksa i ró¿nymi implementacjami pow³oki. • Podstawowe elementy skryptów pow³oki • Wyszukiwanie i zastêpowanie fragmentów tekstów • Stosowanie wyra¿eñ regularnych • Korzystanie z potoków • Instrukcje warunkowe • Definiowanie i stosowanie zmiennych • Przetwarzanie plików • Standardowe wejœcie i wyjœcie • Korzystanie z mo¿liwoœci awk • Przenoszenie skryptów pomiêdzy ró¿nymi pow³okami • Bezpieczeñstwo skryptów pow³oki Ksi¹¿ka „Programowanie skryptów pow³oki” zawiera wszystkie informacje niezbêdne do mistrzowskiego opanowania narzêdzi oferowanych przez systemy uniksowe. Spis treści Przedmowa .................................................................................................................... 7 Wstęp .............................................................................................................................9 1. Tło historyczne .............................................................................................................21 21 24 26 1.1. Historia systemu Unix 1.2. Filozofia narzędzi programowych 1.3. Podsumowanie 2. Zaczynamy ................................................................................................................... 27 27 28 28 29 31 42 43 44 47 2.1. Języki skryptowe a języki kompilowane 2.2. Po co nam skrypty powłoki? 2.3. Prosty skrypt 2.4. Autonomia skryptów — wiersz #! 2.5. Podstawowe konstrukcje powłoki 2.6. Odwołania do argumentów skryptów 2.7. Śledzenie wykonania skryptu 2.8. Umiędzynarodowienie i lokalizacja 2.9. Podsumowanie 3. Wyszukiwanie i podstawianie ...................................................................................49 49 51 75 84 3.1. Wyszukiwanie tekstu 3.2. Wyrażenia regularne 3.3. Manipulowanie polami 3.4. Podsumowanie 4. Narzędzia przetwarzania tekstu ................................................................................ 87 87 95 96 97 98 104 105 4.1. Sortowanie tekstu 4.2. Usuwanie duplikatów 4.3. Formatowanie akapitów 4.4. Zliczanie wierszy, słów i znaków 4.5. Drukowanie 4.6. Wycinanie początkowych i końcowych wierszy pliku 4.7. Podsumowanie 3 5. Niezwykła moc potoków ...........................................................................................107 107 114 120 121 124 127 5.1. Wyłuskiwanie danych ze strukturalizowanych plików tekstowych 5.2. Strukturalizacja danych dla potrzeb WWW 5.3. Gierki słowne i krzyżówki 5.4. Słowniki 5.5. Znaczniki 5.6. Podsumowanie 6. Zmienne, podejmowanie decyzji i powtarzanie operacji .........................................129 129 140 148 149 155 158 6.1. Zmienne w obliczeniach arytmetycznych 6.2. Kody powrotne poleceń i funkcji 6.3. Instrukcja case 6.4. Pętle 6.5. Funkcje 6.6. Podsumowanie 7. Wejście i wyjście, pliki i przetwarzanie poleceń ....................................................... 161 161 162 164 168 173 176 182 183 190 197 7.1. Standardowe wejście, wyjście i wyjście diagnostyczne 7.2. Wczytywanie wierszy danych — read 7.3. Jeszcze o przekierowywaniu 7.4. Jeszcze o poleceniu printf 7.5. Rozwijanie tyldy i symbole wieloznaczne 7.6. Podstawianie poleceń 7.7. Cytaty w powłoce 7.8. Etapy przetwarzania poleceń i polecenie eval 7.9. Polecenia wbudowane 7.10. Podsumowanie 8. Skrypty produkcyjne ..................................................................................................199 199 213 242 8.1. Przeszukiwanie ścieżki 8.2. Automatyczna kompilacja oprogramowania 8.3. Podsumowanie 9. Nieuzbrojony a niebezpieczny — awk .....................................................................243 244 245 246 256 258 260 264 272 9.1. Wywołanie awk 9.2. Model programistyczny awk 9.3. Elementy programu 9.4. Rekordy i pola 9.5. Wzorce i akcje 9.6. „Jednowierszowce” w awk 9.7. Instrukcje awk 9.8. Funkcje definiowane przez użytkownika 4 | Spis treści 9.9. Funkcje operujące na ciągach 9.10. Funkcje matematyczne 9.11. Podsumowanie 275 283 285 10. Praca z plikami ........................................................................................................... 287 287 292 294 298 312 313 317 325 10.1. Generowanie list plików 10.2. Aktualizacja czasu modyfikacji 10.3. Tworzenie i stosowanie plików tymczasowych 10.4. Wyszukiwanie plików 10.5. Uruchamianie poleceń — xargs 10.6. Informacje o zajętości systemu plików 10.7. Porównywanie plików 10.8. Podsumowanie 11. Z życia wzięte — scalanie baz danych kont systemowych ..................................... 327 327 328 329 335 339 341 11.1. Problem 11.2. Pliki kont 11.3. Scalanie plików kont 11.4. Aktualizacja uprawnień dostępu do plików 11.5. Kwestie poboczne 11.6. Podsumowanie 12. Sprawdzanie pisowni ................................................................................................343 343 344 345 348 367 12.1. Program spell 12.2. Prototyp oryginalnego uniksowego programu kontroli pisowni 12.3. Ulepszenia, rozszerzenia, ispell i aspell 12.4. Kontrola pisowni w awk 12.5. Podsumowanie 13. Procesy .......................................................................................................................369 370 371 377 384 388 389 394 395 13.1. Tworzenie procesu 13.2. Listy procesów 13.3. Tworzenie i usuwanie procesu 13.4. Śledzenie wywołań systemowych 13.5. Mechanizmy rozliczania procesów 13.6. Opóźnianie i planowanie wykonania procesów 13.7. System plików /proc 13.8. Podsumowanie 14. Przenośność skryptów i rozszerzenia powłoki ........................................................ 397 397 401 14.1. Kruczki 14.2. Polecenie shopt (powłoka bash) Spis treści | 5 14.3. Rozszerzenia wspólne 14.4. Pobieranie i instalacja 14.5. Inne rozszerzone powłoki wzorowane na powłoce Bourne’a 14.6. Wersje powłoki 14.7. Inicjalizacja i finalizacja sesji powłoki 14.8. Podsumowanie 405 417 421 421 422 428 15. Bezpieczeństwo skryptów powłoki ......................................................................... 431 431 434 436 437 439 440 15.1. Wskazówki dla piszących skrypty powłoki 15.2. Powłoki okrojone 15.3. Konie trojańskie 15.4. Skrypty powłoki z bitem setuid 15.5. Tryb uprzywilejowany w ksh93 15.6. Podsumowanie A Tworzenie dokumentacji dla systemu man .............................................................443 B Pliki i systemy plików ................................................................................................ 457 C Najważniejsze polecenia systemu Unix ...................................................................493 Bibliografia ................................................................................................................499 Słowniczek .................................................................................................................505 Skorowidz .................................................................................................................. 533 6 | Spis treści ROZDZIAŁ 9. Nieuzbrojony a niebezpieczny — awk Język programowania awk powstał jako narzędzie upraszczania wielu powszechnie wyko- nywanych zadań programistycznych związanych z przetwarzaniem tekstu. W niniejszym roz- dziale omówimy tę jego część, którą wykorzystuje się najczęściej w skryptach powłoki, rów- nież tych prezentowanych w tej książce. Pełnego omówienia języka programowania awk należy szukać w jednej z poświęconych mu w całości książek, wymienionych w bibliografii. Jeśli zaś w danym systemie zainstalowana jest wersja GNU awk (gawk), warto też zajrzeć do dołączonej doń dokumentacji, dostępnej za pośrednictwem systemu info1. Wszystkie systemy z rodziny Unix są wyposażone w przynajmniej jedną implementację awk. Po znaczącym rozszerzeniu języka, mającym miejsce w połowie lat osiemdziesiątych, doszło do pewnego rozłamu: niektórzy producenci systemów zachowali implementację pierwotną, instalując ją jako awk albo oawk, a nową wersję udostępnili pod nazwą nawk — w systemach AIX (IBM) i Solaris (Sun) ta praktyka została podtrzymana po dziś dzień. Jednak w większo- ści innych wydań instalowane są jedynie nowsze wersje awk. W systemie Solaris wersja zgodna z POSIX instalowana jest jako /usr/xpg4/bin/awk. W niniejszej książce będziemy omawiać wersję rozszerzoną i będzie ona tu występować jako awk — w konkretnym systemie będzie to zaś albo nawk, albo gawk, albo np. mawk. Musimy się tu jako autorzy przyznać do wielkiej zażyłości z awk. Całymi latami implemen- towaliśmy go, opiekowaliśmy się implementacjami, przenosiliśmy je na inne platformy, pi- sywaliśmy o nim i wreszcie wykorzystywaliśmy we własnych projektach. Większość pro- gramów języka awk to programy króciutkie, ale zdarzyło się nam popełnić i takie, które miały po parę tysięcy wierszy. Prostota i siła awk sprawiają, że jest on obowiązkowym elementem przybornika programisty uniksowego. Rzadko zdarzają się też takie zadania z dziedziny przetwarzania tekstów, w których potrzebna byłaby funkcja czy cecha nieobecna w języku (albo nie dałoby się jej prosto zaimplementować samodzielnie). Parokrotnie stanęliśmy w ob- liczu zadania przepisania programu w języku awk na jeden z konwencjonalnych języków kompilowanych, jak C czy C++ — programy te były zawsze znacznie dłuższe, znacznie trudniejsze do analizy i diagnostyki, tyle że działały nieco szybciej. 1 Pogram info to czytnik dokumentacji GNU, stanowiący część pakietu texinfo, dostępnego pod adresem ftp://ftp.gnu.org/gnu/texinfo/. Do przeglądania tejże dokumentacji można też wykorzystać edytor tekstów emacs — wystarczy w sesji programu emacs nacisnąć klawisze Ctrl+H — przyp. autora. 243 W przeciwieństwie do większości innych języków skryptowych awk doczekał się wielu roz- maitych implementacji, co należy uznać za zaletę, bo programiści otrzymują zawsze taki sam, wspólny rdzeń języka i równocześnie dysponują swobodą wyboru takiej implementacji, która najlepiej odpowiada ich potrzebom. Do tego awk jest częścią standardu POSIX i doczekał się przeniesienia implementacji również na systemy operacyjne spoza rodziny Unix. Jeśli w danym systemie zainstalowana jest wersja awk pochodząca sprzed ustalenia standar- du, warto zaopatrzyć się w jedną z darmowych implementacji wymienionych w tabeli 9.1. Wszystkie one są przenośne i wyjątkowo łatwe w instalacji. Implementacja gawk służyła za poligon testowy dla szeregu ciekawych nowych funkcji wbudowanych i cech języka, w tym implementacji sieciowych operacji wejścia-wyjścia, jak również mechanizmów profilowania, umiędzynaradawiania i kontroli przenośności. Tabela 9.1. Dostępne nieodpłatnie wersje awk Program Wersja awk z laboratoriów Bella gawk mawk awka (translator awk – C) Położenie http://cm.bell-labs.com/who/bwk/awk.tar.gz ftp://ftp.gnu.org/gnu/gawk/ ftp://ftp.whidbey.net/pub/brennan/mawk-1.3.3.tar.gz http://awka.sourceforge.net/ 9.1. Wywołanie awk W wywołaniu interpretera awk można definiować zmienne, określać kod programu i wska- zywać nazwy plików wejściowych: awk [ -F sep ] [ -v zmienna=wartość ... ] program [ -- ] [ zmienna=wartość ... ] [ plik ... ] awk [ -F sep ] [ -v zmienna=wartość ... ] -f plik-programu [ -- ] [ zmienna=wartość ... ] [ plik ... ] Krótkie programy są najczęściej przekazywane do interpretera z poziomu wiersza wywoła- nia; dłuższe zapisuje się w pliku i wskazuje ów plik za opcją -f. Opcja ta może zostać powtó- rzona — w takim przypadku interpreter złoży program, konkatenując ze sobą zawartość po- szczególnych plików. Można dzięki temu konstruować i wykorzystywać biblioteki kodu w języku awk. Do włączania bibliotek można też wykorzystać program igawk, wchodzący w skład dystrybucji gawk. Wszelkie opcje wywołania awk muszą znaleźć się przed plikami i pa- rami zmienna=wartość. Jeśli wywołanie nie określa plików wejściowych, interpreter będzie wczytywał dane ze stan- dardowego wejścia. Opcja w postaci -- nie jest obowiązkowym elementem wywołania; jeśli występuje, oznacza koniec opcji wywołania interpretera awk. Wszelkie opcje umieszczone za tym symbolem sta- nowią opcje programu. Opcja -F pozwala na zmianę domyślnego separatora pól. Przyjęło się, że jeśli już występuje, to jako pierwsza z opcji wywołania interpretera awk. Jej argumentem jest wartość sep, będąca wyrażeniem regularnym i umieszczona bezpośrednio za -F, albo występująca jako następny argument wywołania. Separator pól można też ustawić przypisaniem do wbudowanej zmiennej FS (zobacz tabelę 9.3, w której wymienione zostały zmienne skalarne awk): awk -F { ... } pliki FS= [fv] pliki 244 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk W powyższym wywołaniu przy przetwarzaniu pierwszego zestawu plików będzie obowią- zywał separator pól ustalony opcją -F. Separator ustawiony przypisaniem do zmiennej FS będzie zaś obowiązywał przy przetwarzaniu drugiego zestawu plików. Przypisania do zmiennych podawane z opcją -v muszą poprzedzać wszelki kod programu przekazywany jawnie w wierszu wywołania; przypisania te są realizowane jeszcze przed uruchomieniem programu i przed przystąpieniem do przetwarzania plików wejściowych. Kiedy opcja -v występuje za kodem programu, jest interpretowana jako nazwa pliku (z oczywistych względów najprawdopodobniej nieistniejącego). Przypisania określone w innych miejscach wiersza wywołania są realizowane w miarę prze- twarzania argumentów; mogą być przetykane nazwami plików, jak tutaj: awk {...} zm=1 *.tex zm=2 *.tex W powyższym wywołaniu pliki ∗.tex zostaną przetworzone dwukrotnie — raz z ustawie- niem zm na jeden i drugi raz, po ustawieniu zm na dwa. Wartości inicjalizujące zmienne ciągami znaków nie muszą być ujmowane w znaki cudzy- słowu, chyba że jest to wymagane ze względu na mechanizmy powłoki, na przykład do za- chowania znaków specjalnych czy odstępów. Specjalna nazwa pliku wejściowego w postaci myślnika (-) reprezentuje standardowe wejście. Większość współczesnych implementacji awk rozpoznaje nazwę pliku specjalnego /dev/stdin; reprezentuje ona standardowe wejście nawet w tych systemach, które nie rozpoznają tej na- zwy jako nazwy istniejącego pliku. Podobnie jest z nazwami /dev/stderr i /dev/stdout, które w wywołaniu awk reprezentują standardowe wyjście i standardowe wyjście diagnostyczne. 9.2. Model programistyczny awk Interpreter awk postrzega strumień danych wejściowych jako kolekcję rekordów, z których każdy da się podzielić na pola. Zwykle rekord pokrywa się z pojedynczym wierszem, a pole to jedno słowo takiego wiersza (ewentualnie dowolny jedno- lub wieloznakowy ciąg znaków nie będących znakami odstępu). Jednak sposób dzielenia rekordów i pól pozostaje całkowicie pod kontrolą programisty, a ich definicje mogą być zmieniane nawet w trakcie przetwarzania. Program języka awk składa się z par wzorzec-akcja i może być ewentualnie uzupełniony de- finicjami funkcji implementujących szczegółowe operacje w ramach akcji. Za każdym razem, kiedy wzorzec uda się dopasować do wejścia, wykonywana jest skojarzona z wzorcem akcja. Przy tym każdy rekord wejściowy jest przetwarzany z uwzględnieniem wszystkich wzorców. W parze wzorzec-akcja można pominąć zarówno część definiującą wzorzec dopasowania, jak i część definiującą akcję. W tym pierwszym przypadku akcja będzie stosowana do każdego rekordu wejściowego; w obliczu braku akcji dopasowanie wzorca do rekordu zostanie skwi- towane wykonaniem akcji domyślnej, która polega na wypisaniu dopasowanego rekordu na standardowym wyjściu. Oto typowy układ programu awk: wzorzec { akcja } uruchomienie akcji po dopasowaniu wzorca wzorzec wypisanie rekordu dopasowanego do wzorca { akcja } uruchomienie akcji dla każdego rekordu Wejście automatycznie przełącza się pomiędzy wskazanymi plikami wejściowymi. Otwiera- niem plików wejściowych, odczytem danych i zamykaniem plików zajmuje się sam interpre- ter awk, więc programista może skupić się na właściwym problemie — przetwarzaniu rekor- dów. Tym zajmiemy się obszernie w podrozdziale 9.5. 9.2. Model programistyczny awk | 245 Wzorce są najczęściej wyrażeniami liczbowymi albo ciągami, ale awk pozwala też na stoso- wanie dwóch wzorców specjalnych oznaczanych słowami kluczowymi BEGIN i END. Akcja skojarzona z wzorcem BEGIN jest wykonywana jednokrotnie, tuż przed przystąpieniem do przetwarzania plików wejściowych i realizacją wszelkich zwykłych (bez opcji -v) przypi- sań zadanych w wywołaniu, ale już po zrealizowaniu przypisań przekazanych z opcją -v. Zwykle w bloku kodu tej akcji realizuje się specjalne procedury inicjalizacji wymagane przez właściwy program. Akcja skojarzona z END również jest wykonywana tylko jednokrotnie, już po przetworzeniu kompletu danych wejściowych. Zwykle w jej obrębie realizuje się wypisywanie zestawień i pod- sumowań wyników przetwarzania, ewentualnie czynności porządkowe. Wzorce BEGIN i END mogą występować w dowolnej kolejności i gdziekolwiek w programie. Utarło się jednak, aby wzorzec BEGIN stanowił pierwszy wzorzec programu, a wzorzec END kończył program. Jeśli w programie występuje większa liczba wzorców BEGIN i END, są one przetwarzane w kolej- ności, w jakiej występują w programie. Dzięki temu można uzupełniać czynnościami wstępnymi i porządkowymi również kod biblioteczny, włączany do programu dodatkowymi opcjami -f. 9.3. Elementy programu Jak większość skryptowych języków programowania, awk manipuluje przede wszystkim licz- bami i ciągami znaków. W obrębie programu programista może przechowywać dane w zmien- nych skalarnych i tablicowych, ma też do dyspozycji wyrażenia liczbowe i wyrażenia ciągów znaków oraz przypisania, instrukcje warunkowe, wywołania funkcji, instrukcje wejścia-wyjścia, instrukcje pętli i komentarze. Wiele cech instrukcji i wyrażeń awk upodabnia te wyrażenia i instrukcje do ich odpowiedników w języku C. 9.3.1. Komentarze i odstępy Komentarze w awk oznacza się znakiem kratki (#). Komentarz rozciąga się od tego znaku do końca wiersza programu — tak, jak w skryptach powłoki. Wiersze puste są odpowiednikami pustych komentarzy. Tam, gdzie składnia języka przewiduje stosowanie odstępów, można umieścić dowolną liczbę znaków odstępów. Można dzięki temu pustymi wierszami i wcięciami uwypuklać strukturę programu gwoli większej czytelności. Zwykle jednak nie można rozbijać pojedynczej instrukcji na wiele wierszy — chyba że znaki nowego wiersza będą w nich bezpośrednio poprzedzane znakami lewego ukośnika. 9.3.2. Ciągi i wyrażenia ciągów Ciągi znaków, czyli stałe łańcuchowe, są w awk ograniczane znakami podwójnego cudzysło- wu: To jest ciag znakow . Ciągi znaków mogą zawierać dowolne 8-bitowe znaki, z wy- jątkiem sterującego znaku pustego (znaku o wartości 0), który w języku C (a w nim pisany jest interpreter awk) służy za znak końca ciągu. W implementacji GNU gawk ograniczenie to zostało zniesione; dzięki temu gawk może bezpiecznie przetwarzać dowolne pliki binarne. 246 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk Ciąg w awk może zawierać zero albo więcej znaków; jego długość nie jest ograniczona niczym poza ilością dostępnej pamięci. Przypisanie wyrażenia ciągu znaków do zmiennej automa- tycznie tworzy ciąg znaków i przydziela mu pamięć. Pamięć zajmowana przez poprzednią wartość zmiennej jest zaś automatycznie zwalniana. Do reprezentowania znaków niedrukowalnych służą sekwencje sterujące sygnalizowane znakiem lewego ukośnika, podobnie, jak to miało miejsce w argumentach polecenia echo (zobacz punkt 2.5.3). Ciąg A Z zawiera więc znak A, znak tabulacji i znak Z, a ciągi 01 i x01 zawierają znak Ctrl+A. W echo brak obsługi sekwencji sterujących z wartościami szesnastkowymi. W awk są one rozpoznawane, przynajmniej w implementacjach bazujących na wprowadzonym w 1989 ro- ku standardzie ISO C. W przeciwieństwie do ósemkowych sekwencji sterujących składają- cych się z najwyżej trzech znaków, sekwencje szesnastkowe obejmują wszystkie stanowiące zwarty podciąg cyfry szesnastkowe. Tak jest w gawk i nawk. Z reguły tej wyłamuje się mawk: tu sekwencja szesnastkowa jest ograniczona do najwyżej dwóch cyfr, co redukuje ciąg x404142 do postaci @4142 . Gdyby nie ograniczenie długości sekwencji szesnastkowej do dwóch cyfr, ciąg ten zostałby zinterpretowany jako @AB . Implementacje awk zgodne ze standardem POSIX w ogóle nie obsługują szesnastkowych sekwencji sterujących. Interpreter awk wspomaga operacje na ciągach szeregiem wygodnych i użytecznych funkcji wbudowanych; omawiamy je w podrozdziale 9.9. Na razie wspomnimy choćby o funkcji ob- liczającej długość ciągu: wywołanie length(ciąg) zwraca liczbę znaków w ciągu ciąg. Ciągi można porównywać tradycyjnym zestawem operatorów relacji: == (równe), != (różne), (mniejszy niż), = (mniejszy lub równy), (większy), = (większy lub równy). Operatory relacji zwracają zero (wartość logiczna „prawda”), kiedy relacja jest spełniona dla zadanych operandów, albo 1 (logiczny „fałsz”), kiedy relacja pozostaje niespełniona. Kiedy porównuje się ciągi o różnej długości i jeden z tych ciągów stanowi podciąg drugiego, krótszy z nich obu jest uznawany za „mniejszy” niż dłuższy. Stąd A AA daje spełnioną relację i wartość logiczną „prawda”. W większości języków programowania obsługujących typy łańcuchowe stosuje się specjalny operator konkatenacji ciągów. W awk nie ma takiego specjalnego operatora — konkatenacji poddawane są automatycznie wszelkie sąsiadujące ze sobą ciągi znaków. Każde z poniższych przypisań ustawia więc zmienną s na ten sam czteroznakowy ciąg: s = ABCD s = AB CD s = A BC D s = A B C D Automatyczna konkatenacja obejmuje nie tylko stałe (literały) łańcuchowe. Gdyby poprzednie przypisania uzupełnić poniższym: t = s s s zmienna t otrzymałaby wartość ABCDABCDABCD . Konwersja liczby na ciąg odbywa się niejawnie, przez konkatenację literału liczbowego z ciągiem pustym: n = 123 uzupełnione przypisaniem s = n, powoduje przypisanie do s ciągu 123 . Trzeba tu uważać na liczby, których nie da się dokładnie reprezentować — zajmiemy się tym w punkcie 9.9.8, przy okazji omawiania formatowanej konwersji liczby na ciąg. 9.3. Elementy programu | 247 Znaczna część potęgi awk wynika z implementowanej w tym języku obsługi wyrażeń regu- larnych. Ich wykorzystanie jest ułatwione przez dwa operatory: ~ (dopasowanie) i !~ (brak dopasowania). Wyrażenie ABC ~ ^[A-Z]+$ daje wartość „prawda”, bo ciąg występujący w roli lewego operandu zawiera wyłącznie znaki wielkich liter, a wyrażenie regularne zada- ne prawym operandem dopasowuje właśnie ciągi wielkich liter ASCII (o dowolnej długości). W awk można korzystać z rozszerzonych wyrażeń regularnych ERE (Extended Regular Expressions), opisywanych w punkcie 3.2.3. Wyrażenia regularne mogą być ograniczane albo parą znaków cudzysłowu, albo ukośników: ABC ~ /^[A-Z]+$/. Wybór jednej z tych konwencji jest kwestią gustu i wygody programi- sty, choć w sumie preferowana jest forma z ukośnikami, bo uwypukla ona fakt, że ujęty po- między nimi ciąg jest wyrażeniem regularnym, a nie zwykłym literałem łańcuchowym. Są jednak przypadki, w których znak ukośnika ograniczający wyrażenie regularne może zostać pomylony z operatorem dzielenia — tam należałoby stosować znaki cudzysłowu. Znak cudzysłowu w obrębie ciągu ograniczonego takimi znakami, jeśli ma zostać potrakto- wany dosłownie, powinien zostać poprzedzony znakiem ukośnika lewego ( ... ... ), to samo tyczy się znaków ukośnika w wyrażeniach ograniczanych parą znaków ukośnika (/.../.../). Oczywiście również znak lewego ukośnika, kiedy ma być traktowany dosłow- nie, musi zostać poprzedzony takim znakiem, a w wyrażeniach ograniczanych znakami cu- dzysłowu nawet kilkoma: \\Tex i /\Tex/ reprezentują to samo wyrażenie regularne dopasowujące ciąg Tex. 9.3.3. Liczby i wyrażenia liczbowe Wszelkie liczby w programie awk są reprezentowane jako wartości zmiennoprzecinkowe po- dwójnej precyzji, o których więcej można się dowiedzieć z sąsiedniej ramki. Programista awk nie musi być bynajmniej ekspertem w dziedzinie arytmetyki zmiennoprzecinkowej, ale waż- ne, aby zdawał sobie sprawę z charakterystycznych dla niej (i ogólnie dla arytmetyki reali- zowanej przez komputery) ograniczeń i aby nie oczekiwał od komputera nieosiągalnej dla niego dokładności, a przy okazji uniknął kilku pułapek. Liczby zmiennoprzecinkowe mogą zawierać wykładnik za literą e (albo E) i część całkowitą, z ewentualnym znakiem. Na przykład wartość ułamka 1/32 można reprezentować warto- ściami zmiennoprzecinkowymi 0.03125, 3.125e-2, 3125e-5 albo 0.003125E1. Ponieważ wszelka arytmetyka w awk to arytmetyka zmiennoprzecinkowa, wyrażenie 1/32 można zapi- sać w ten sposób bez ryzyka, że przyjmie wartość zerową, jak to bywa w językach programo- wania bazujących na arytmetyce liczb całkowitych. Nie istnieje funkcja jawnej konwersji ciągu na wartość liczbową, ale w awk nie jest to proble- mem: wystarczy do ciągu znaków reprezentującego liczbę dodać zero. Na przykład przypi- sanie s = 123 , uzupełnione przypisaniem n = 0 + s, zaowocuje przypisaniem do zmien- nej n wartości liczbowej 123. Ciągi są konwertowane na liczby, o ile tylko zawartość ciągu, albo jego część, choćby przy- pomina liczbę: +123ABC da się konwertować na wartość 123, a ciągi ABC , ABC123 i mają wartość liczbową 0. 248 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk Więcej o arytmetyce zmiennoprzecinkowej Współcześnie praktycznie wszystkie platformy sprzętowe są zgodne ze standardem binarnej arytmetyki zmiennoprzecinkowej według ustalonego w 1985 roku standardu IEEE 754 (Stan- dard for Binary Floating-Point Arithmetic). Standard ten definiuje 32-bitowy format pojedyn- czej precyzji, 64-bitowy format podwójnej precyzji i opcjonalny format precyzji rozszerzonej, implementowany zwykle na 80 lub 128 bitach. Implementacje awk korzystają zazwyczaj z 64- bitowego formatu (odpowiadającego typowi double z języka C), choć ze względu na prze- nośność specyfikacja języka awk nie narzuca żadnych szczegółów w tym zakresie. Specyfika- cja standardu POSIX mówi zaś jedynie, że implementacja arytmetyki powinna być zgodna ze standardem ISO C, który nie narzuca żadnej architektury zmiennoprzecinkowej. Wartości formatu podwójnej precyzji wg IEEE 754 posiadają bit znaku, 11-bitowy wykładnik i 53-bitową mantysę, której najstarszy bit nie jest zachowywany. Pozwala to na reprezento- wanie szesnastocyfrowych liczb dziesiętnych. Maksimum skończonej wielkości dającej się reprezentować w tym formacie przypada na 10+308, a najmniejsza znormalizowana niezero- wa wartość to 10-308. Większość implementacji IEEE 754 obsługuje dodatkowo wartości nie- znormalizowane, rozszerzające zakres reprezentacji do 10-324, ale kosztem precyzji — ów stopniowy niedomiar do zera ma zresztą kilka własności, które choć pożądane w oprogramo- waniu stricte obliczeniowym, w innych zastosowaniach są nieistotne. Z racji jawnego reprezentowania znaku liczby osobnym bitem arytmetyka zmiennoprzecin- kowa IEEE 754 rozróżnia dwie wartości zerowe: dodatnią i ujemną. W większości języków programowania jest to ignorowane; awk nie jest wyjątkiem: niektóre implementacje wypisują ujemne zero bez znaku minusa. Arytmetyka IEEE 754 uwzględnia również dwie specjalne wartości reprezentujące nieskoń- czoność i wartość nieliczbową (NaN, od ang. not a number). Obie mogą występować ze zna- kiem, choć znak wartości nieliczbowej jest ignorowany. Wartości te są wykorzystywane do wykonywania nieprzerwanych ciągów obliczeń na wysokowydajnych komputerach przy za- chowaniu możliwości rejestrowania stanów wyjątkowych. Kiedy liczba jest zbyt duża, aby dało się ją skutecznie reprezentować, wynikiem jest nieskończoność, a dodatkowo procesor ustawia znacznik przepełnienia. W przypadku wartości niezdefiniowanych, jak nieskończo- ność-nieskończoność albo 0/0, wynikiem jest wartość nieliczbowa. Nieskończoność i wartość nieliczbowa podlegają propagacji w obliczeniach: nieskończoność + nieskończoność oraz nieskończoność * nieskończoność dają nieskończoność, a jakakolwiek operacja arytmetyczna angażująca wartość nieliczbową daje w wyniku wartość nieliczbową. Porównanie dwóch nieskończoności o tym samym znaku daje równość. Porównanie dwóch wartości nieliczbowych daje różność; dla x będącego wartością nieliczbową spełniona jest więc relacja (x != x). Język awk powstał przed upowszechnieniem się standardu IEEE 754, przez co język nie ob- sługuje w pełni nieskończoności i wartości nieliczbowych. W szczególności w bieżących im- plementacjach awk próba dzielenia przez zero prowokuje wyjątek — mimo że wedle reguł arytmetyki IEEE 754 nie ma takiej konieczności. Ograniczona precyzja wartości zmiennoprzecinkowych oznacza niemożność dokładnego reprezentowania niektórych liczb: liczy się przy tym kolejność wartościowania (arytmetyka zmiennoprzecinkowa nie podlega łączności), a obliczone wyniki są zwykle zaokrąglane do najbliższej wartości dającej się dokładnie reprezentować. 9.3. Elementy programu | 249 Ograniczony zakres reprezentacji wartości zmiennoprzecinkowych oznacza z kolei, że warto- ści bardzo wielkie i bardzo małe również nie dają się dokładnie reprezentować. We współ- czesnych systemach wartości te są konwertowane na (odpowiednio) nieskończoność i zero. Choć obliczenia realizowane z poziomu programu awk wykonywane są wedle reguł arytme- tyki zmiennoprzecinkowej, nie znaczy to, że nie można posługiwać się wartościami całkowi- toliczbowymi — będą one reprezentowane dokładnie, o ile tylko będą utrzymywane w odpo- wiednim zakresie. Arytmetyka zmiennoprzecinkowa IEEE 754 przy 53-bitowej mantysie pozwala na reprezentowanie wartości całkowitych z zakresu od 0 do 253, czyli 9 007 199 254 740 992. Liczba ta jest w zastosowaniach związanych z przetwarzaniem tekstu aż nadto wy- starczająca — ryzyko wyczerpania zakresu w wyniku np. zliczania jest bardzo nikłe. Zbiór operatorów arytmetycznych języka awk odzwierciedla podobne zbiory znane z innych języków programowania. Komplet operatorów wymienia tabela 9.2. Tabela 9.2. Operatory arytmetyczne języka awk (według priorytetu) Operator ++ -- ^ ** ! + - * / + - = == != = || ? : = += -= *= /= = ^= **= Działanie Inkrementacja i dekrementacja (w wersji przed- albo przyrostkowej). Potęgowanie (łączność prawostronna). Negacja, jednoargumentowe operatory znaku. Mnożenie, dzielenie, reszta z dzielenia. Dodawanie, odejmowanie. Operatory relacji. Logiczny iloczyn (AND — ze skróconym wartościowaniem). Logiczna suma (OR — również ze skróconym wartościowaniem). Operator wykonania warunkowego. Operatory przypisania (prawostronnie łączne). Jak w większości języków programowania, kolejność stosowania operatorów można modyfi- kować nawiasami. Mało kto rozeznaje się dokładnie we wzajemnym pierwszeństwie po- szczególnych operatorów; dotyczy to zwłaszcza parających się programowaniem w różnych językach. Rada jest jedna: w razie wątpliwości, stosować nawiasy! Operatory inkrementacji i dekrementacji działają identycznie, jak w powłoce (zostało to omówione w punkcie 6.1.3). Wyrażenia ++n i n++, jeśli występują w odosobnieniu, są sobie co do ostatecznego efektu równoważne. Jednak z racji efektu ubocznego — bo obok zwrócenia wartości zmiennej rzeczone operatory modyfikują tę wartość — wielokrotne wystąpienia operatorów inkrementacji i dekrementacji w obrębie jednego wyrażenia mogą zaistnieć nie- jednoznaczności wynikające z kolejności wartościowania. Wynik wyrażenia n++ ++n jest więc zależny od implementacji. Mimo tego rodzaju niejednoznaczności operatory inkrementacji i dekrementacji są powszechnie wykorzystywane nie tylko w awk, ale we wszystkich obsłu- gujących je językach programowania. Operatory potęgowania podnoszą lewy operand do potęgi określonej prawym operandem. Stąd zarówno n^3, jak i n**3 oznacza podniesienie wartości n do sześcianu. Oba operatory są sobie równoważne, choć mają różne korzenie — wywodzą się z różnych języków programo- wania. Programiści języka C powinni pamiętać, że operator ^, mimo swojego podobieństwa do podobnie zapisywanego operatora z języka C, różni się od niego działaniem. 250 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk Potęgowanie i operacje przypisania to jedyne operatory awk cechujące się łącznością prawo- stronną. Łączność taka oznacza, że a^b^c^d to tyle, co a^(b^(c^d)), podczas gdy a/b/c/d oznacza tyle, co ((a/b)/c)/d. Reguły łączności są zbieżne z tymi stosowanymi w większości pozostałych języków programowania, stanowią też konwencję przyjętą w matematyce. W pierwotnej specyfikacji awk wynik działania operatora reszty z dzielenia w przypadku, kiedy jeden z operandów był ujemny, był zależny od implementacji. POSIX wymaga, aby implementacja awk zachowywała się zgodnie ze standardem ISO C w zakresie ustalonym dla funkcji fmod(). Specyfikacja ta zakłada, że jeśli wartość x y daje się w ogóle reprezentować, to posiada znak wartości x i wartość bezwzględną nie większą od y. Wszystkie testowane przez nas implementacje awk zachowywały się zgodnie z wymogami POSIX. Tak, jak w powłoce, operatory logiczne i || podlegają skróconemu wartościowaniu — wartość logiczna prawego operandu jest obliczana wyłącznie w przypadku, kiedy nie można ustalić wartości operacji na podstawie samego lewego operandu. Operator z przedostatniego wiersza tabeli 9.2 to trójargumentowy operator warunkowy, któ- ry również stosuje regułę skróconego wartościowania. Otóż jeśli pierwszy z operandów ma wartość logiczną „prawda”, to wynikiem operatora jest drugi operand; w innym przypadku operator zwraca wartość trzeciego operandu. Tak czy inaczej, z dwóch (drugiego i trzeciego) operandów wartościowany jest zawsze tylko jeden. Dzięki temu można w awk w zwarty spo- sób zapisać następujące przypisanie: a = (u w) ? x^3 : y^7. W innych językach pro- gramowania wymagałoby to skonstruowania następującej instrukcji warunkowej: if (u w) then a = x^3 else a = y^7 endif Ciekawe są operatory przypisania, a to z dwóch powodów. Po pierwsze, ich wersje złożone, jak /=, wykorzystują lewy operand w roli brakującego pierwszego operandu po lewej stronie przypisania; zapis n /= 3 to w istocie skrócone przypisanie n = n / 3. Po drugie, wartość zwracana przez operator przypisania może być wykorzystywana jako część wyrażenia; na przykład wyrażenie a = b = c = 123 powoduje najpierw przypisanie wartości 123 do zmiennej c, potem przypisanie wartości c (123) do zmiennej b i wreszcie przypisanie bieżącej wartości b (również 123) do a (wszystko dzięki prawostronnej łączności operatora przypisa- nia). W efekcie wszystkie trzy zmienne (a, b i c) otrzymują wartość 123. Podobnie należy in- terpretować wyrażenie x = (y = 123) + (z = 321), ustawiające zmienne x, y i z na (od- powiednio) 444, 123 i 321. Operatory ** i **= nie są ujęte specyfikacją POSIX i jako takie nie są rozpoznawane przez mawk. Dlatego też należałoby unikać ich stosowania, zastępując je operatorami ^ i ^=. Nie wolno zapominać o zasadniczej różnicy pomiędzy operatorem przypisania (=) a podobnie wyglądającym (i często omyłkowo zapisywanym) operatorem równości (==). Ponieważ przypisania są jak najbardziej poprawnymi wyrażeniami, wyrażenie (r = s) ? t : u jest co prawda składniowo poprawne, ale zapewne zostało tak zapisane w wyniku omyłki. Realizuje ono bowiem przypisanie s do r, a jeśli wartość r będzie niezerowa, całość wyrażenia przyjmie wartość t; w innym przypadku ca- łość przyjmie wartość u. Ostrzeżenie to dotyczy również języków C, C++ i Java, w których równie łatwo o zgubną w skutkach pomyłkę w zapisie operatorów = i ==. 9.3. Elementy programu | 251 Część całkowitą argumentu można wyłuskać z wartości liczbowej za pośrednictwem wbu- dowanej funkcji int(): wywołanie int(-3.14159) zwraca wartość -3. Język awk udostępnia też programistom zestaw podstawowych funkcji matematycznych, zna- nych z kalkulatorów i innych języków programowania; mowa o sqrt(), sin(), cos(), log(), exp() i tym podobnych. Kompletny ich przegląd znajduje się w podrozdziale 9.10. 9.3.4. Zmienne skalarne Zmienne skalarne to takie zmienne, które mogą przechowywać pojedynczą wartość. W języku awk, na wzór wielu innych języków skryptowych, zmiennych nie trzeba jawnie deklarować. Zmienne tworzone są automatycznie, w momencie kiedy po raz pierwszy pojawiają się w pro- gramie, zwykle w wyrażeniu przypisania wartości do zmiennej. Do zmiennej można przypisać wartość liczbową albo ciąg znaków. W miejscu użycia zmiennej kontekst określa, czy zmienna ma być interpretowana jako ciąg, czy liczba — interpreter automatycznie dokonuje stosownej konwersji. Nowo tworzone zmienne programu języka awk są inicjalizowane ciągiem pustym, który licz- bowo daje wartość zerową. Nazwy zmiennych awk muszą rozpoczynać się od znaku litery ASCII albo znaku podkreśle- nia, na dalszych pozycjach mogą zaś zawierać również litery, znaki podkreślenia oraz cyfry. Słowem, nazwy zmienne muszą dać się dopasować do wyrażenia regularnego [A-Za-z_ ][A-Za-z0-9_]*. Język nie narzuca przy tym ograniczenia co do długości nazwy zmiennej. W nazwach zmiennych w awk rozróżnia się wielkie i małe litery: cos, Cos i COS to trzy różne nazwy. Utarło się, że nazwy zmiennych lokalnych zawierają tylko małe litery, nazwy zmiennych globalnych rozpoczyna się wielką literą, a w nazwach zmiennych wbudowanych występują wyłącznie wielkie litery. Zgodnie z powyższym, awk rezerwuje kilka zmiennych wbudowanych (ich nazwy zawierają rzecz jasna same wielkie litery). Najważniejsze z nich, wykorzystywane często nawet w pro- stych programach, zostały wymienione w tabeli 9.3. Tabela 9.3. Najczęściej stosowane zmienne wbudowane awk Zmienna FILENAME FNR FS NF NR OFS ORS RS Znaczenie Nazwa bieżącego pliku wejściowego. Numer rekordu w bieżącym pliku wejściowym. Separator pól (wyrażenie regularne; domyślnie ). Liczba pól w bieżącym rekordzie. Numer przetwarzanego rekordu. Separator pól na wyjściu (domyślnie ). Separator rekordów na wyjściu (domyślnie ). Separator rekordów na wejściu (w gawk i nawk jest określony wyrażeniem regularnym; domyślnie ). 252 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk 9.3.5. Zmienne tablicowe Reguły nazywania zmiennych tablicowych w awk są identyczne, jak dla zmiennych skalar- nych. Zmienna tablicowa tym się różni od skalarnej, że może przechowywać zero albo więcej elementów danych; odwołania do tych elementów konstruuje się, indeksując nazwę zmiennej tablicowej indeksem elementu. Większość tradycyjnych języków programowania wymaga, aby tablice były indeksowane prostymi wyrażeniami dającymi wartości liczbowe-całkowite. W awk indeksy tablic, ujmo- wane w nawiasach prostokątnych za nazwą zmiennej tablicowej, mogą być dowolnymi wy- rażeniami liczbowymi i wyrażeniami ciągów. Każdemu, dla kogo indeksowanie tablicy do- wolnym typem wyrażenia jest nowością, będzie się to wydawać dziwaczne. Ale wystarczy fragment programu konstruującego katalog biurowy, aby uwidoczniła się cała wygoda tego rozwiązania: telephone[ janusz ] = 123-0123 telephone[ dorotka ] = 123-0146 telephone[ toto ] = 123-0459 telephone[ zbyszko ] = 123-0039 Tablice dające możliwość indeksowania dowolnymi indeksami noszą miano tablic asocjacyjnych, bo dają możliwość kojarzenia wartości elementów z nazwami (tak, jak zwykli to czynić ludzie). Co ważne, implementacja tych tablic w awk gwarantuje wykonywanie operacji wyszukiwania, wstawiania i usuwania elementów tablicy w zasadniczo stałym czasie, niezależnie od liczby elementów przechowywanych w tablicy. Tablice awk nie wymagają ani deklarowania, ani jawnego przydziału pamięci — pamięć tabli- cy jest alokowana dynamicznie, w miarę umieszczania w niej kolejnych elementów. Przy tym przydziały wykonywane są niezależnie dla poszczególnych elementów; dzięki temu można wykonać przypisanie x[1] = 3.14159, a zaraz potem x[10000000] = dziesiec milionow bez prowokowania niepotrzebnego przydziału elementów o indeksach od 2 do 9 999 999. Dalej, w większości języków programowania elementy tablicy muszą być tego samego typu; w awk mamy pod tym względem pełną swobodę. Kiedy elementy tablicy przestaną być potrzebne, przydzieloną do nich pamięć można jawnie zwolnić. Służy do tego instrukcja delete tablica[indeks]. Nowsze implementacje awk udostępniają też instrukcję ogólniejszą, zwalniającą wszystkie elementy tablicy: delete tablica. Jest jeszcze inna metoda usuwania elementów tablicy — zostanie ona przedsta- wiona w punkcie 9.9.6. Zmienna nie może być równocześnie skalarną i tablicową. Instrukcja delete usuwa elementy tablicy, ale nie zmienia charakteru zmiennej tablicowej — usunięcie wszystkich elementów ta- blicy nie zmieni jej w zmienną skalarną, przez co kod, np. taki: x[1] = 123 delete x x = 789 sprowokuje interpreter awk do zgłoszenia komunikatu o niemożności wykonania przypisania wartości do tablicy. Niekiedy do jednoznacznego lokalizowania elementów tablicy trzeba zaprząc więcej niż jeden indeks. Na przykład adresata przesyłki pocztowej identyfikuje się na podstawie numeru domu, nazwy ulicy i kodu pocztowego. Dalej, skojarzenie pary wiersz-kolumna pozwala na zloka- lizowanie pozycji elementu w dwuwymiarowej tabeli, jak na planszy do szachów. Z kolei w 9.3. Elementy programu | 253 bibliografiach poszczególne książki są identyfikowane nazwiskiem autora, tytułem, numerem wydania, nazwą wydawcy oraz rokiem wydania. Z kolei sklepikarz, jeśli ma przynieść na salę sprzedaży konkretną parę butów, musi znać producenta, nazwę modelu, kolor i rozmiar. Tablice o mnogich indeksach można w awk symulować, stosując w roli indeksów ciągi zawie- rające wartości indeksów oddzielanych przecinkami. Ponieważ jednak przecinki mogą wy- stąpić w ciągach poszczególnych indeksów, awk zastępuje przecinki oddzielające indeksy nie- drukowalnym ciągiem przechowywanym we wbudowanej zmiennej SUBSEP. Specyfikacja POSIX mówi, że wartość tej zmiennej jest zależna od implementacji; generalnie przyjęło się, że jest to wartość 34 (znak sterujący separatora pól ASCII — FS), ale można ją dla wła- snych potrzeb dowolnie modyfikować. Kiedy interpreter napotyka zapis adresat[ 48 , Klonowa , 12-212 ], konwertuje listę indeksów na ciąg 48 SUBSEP Klonowa SUBSEP 12-212 i dopiero tak skonstruowany ciąg wykorzystuje w roli indeksu tablicy. Interpreter można wyręczyć, samodzielnie konstruując ciąg indeksu; poniższe instrukcje dają identyczny efekt: print adresat[ 48 , Klonowa , 12-212 ] print adresat[ 48 SUBSEP Klonowa SUBSEP 12-212 ] print adresat[ 4834Klonowa , 12-212 ] print adresat[ 4834Klonowa3412-212 ] Trzeba jednak pamiętać, że ewentualna zmiana wartości zmiennej SUBSEP spowoduje unie- ważnienie indeksów do już zachowanych elementów tablicy. Dlatego zmienną SUBSEP, jeśli już jest to konieczne, należałoby zmieniać tylko raz w każdym programie, najlepiej w ramach sekcji BEGIN. Właściwe stosowanie tablic asocjacyjnych ułatwia rozwiązywanie zaskakująco licznej grupy problemów przetwarzania danych. Dostępność tablic w prostym w sumie języku programo- wania, jakim jest awk, należy uznać za świetne udogodnienie. 9.3.6. Argumenty wywołania programu Automatyzacja obsługi argumentów programu awk oznacza, że programiści korzystający z tego języka rzadko muszą szamotać się z obsługą argumentów wywołania. Odróżnia to awk od języków C, C++, Java czy nawet języka programowania powłoki, gdzie obsługa argu- mentów jest jawna. Interpreter awk udostępnia argumenty wywołania za pośrednictwem wbudowanych zmien- nych ARGC (licznik argumentów) i ARGV (wektor argumentów, czyli tablica wartości argumentów). Ich stosowanie najlepiej zilustrować prostym programem: $ cat showargs.awk BEGIN { print ARGC = , ARGC for (k = 0; k ARGC; k++) print ARGV[ k ] = [ ARGV[k] ] } Powyższy program sprawuje się następująco: $ awk -v Jeden=1 -v Dwa=2 -f showargs.awk Trzy=3 plik1 Cztery=4 plik2 plik3 ARGC = 6 ARGV[0] = [awk] ARGV[1] = [Trzy=3] ARGV[2] = [plik1] ARGV[3] = [Cztery=4] ARGV[4] = [plik2] ARGV[5] = [plik3] 254 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk Tak, jak w C i C++, argumenty wywołania są przechowywane w postaci elementów tablicy indeksowanych od 0 do ARGC - 1; element zerowy to nazwa programu interpretera awk. Tablica argumentów nie obejmuje jednak wartości przekazywanych do interpretera z opcjami -f i -v. Nie zawierałaby również (nieobecnego w powyższym wywołaniu) kodu programu awk: $ awk BEGIN { for (k = 0; k ARGC; k++) print ARGV[ k ] = [ ARGV[k] ] } a b c ARGC = 6 ARGV[0] = [awk] ARGV[1] = [a] ARGV[2] = [b] ARGV[3] = [c] To, czy element zerowy będzie obejmował tylko nazwę pliku wykonywalnego interpretera awk, czy może również ścieżkę dostępu, zależne jest od implementacji: $ /usr/local/bin/gawk BEGIN { print ARGV[0] } gawk $ /usr/local/bin/mawk BEGIN { print ARGV[0] } mawk $ /usr/local/bin/nawk BEGIN { print ARGV[0] } /usr/local/bin/nawk Program awk może zmieniać wartości zmiennych ARGC i ARGV, choć doprawdy rzadko zachodzi rzeczywista potrzeba takich modyfikacji. Jeśli element tablicy ARGV zostanie ustawiony (w wywołaniu albo już w samym programie) na ciąg pusty albo usunięty, awk będzie go ignorował. Przy usuwaniu wpisów (końcowych) z tablicy ARGV należy pamiętać o odpowiednim dostosowaniu wartości ARGC. Interpreter awk zaprzestaje prób interpretacji argumentów jako opcji wywołania, kiedy rozpozna w argumencie kod programu albo specjalną opcję --. Wszelkie argumenty występujące za tymi elementami wywołania, nawet te przypominające opcje, są zostawiane do obsługi programowi awk, który powinien je potem usunąć z ARGV albo zastąpić ciągami pustymi. Wywołanie interpretera z programem awk wygodnie jest niekiedy ująć w skrypcie powłoki. Aby taki skrypt był bardziej cztelny, dłuższe programy należy uprzednio zapisać w zmiennej powłoki. Skrypt można też uogólnić tak, aby pozwalał na dynamiczny wybór implementacji awk na podstawie pewnej zmiennej środowiskowej; oczywiście należałoby wtedy przewidzieć implementację domyślną, np. nawk: #! /bin/sh - AWK=${AWK:-nawk} AWKPROG= ...kod długiego programu... $AWK $AWKPROG $@ Znaki pojedynczego cudzysłowu, otaczające kod programu, zabezpieczają go przed ingeren- cją ze strony powłoki (to jest ewentualnymi podstawieniami). Jeśli jednak sam program ma zawierać znaki pojedynczego cudzysłowu, taka ochrona nie wystarczy. Alternatywą wobec zapisywania kodu programu w zmiennej powłoki jest umieszczenie go w osobnym pliku w wydzielonym katalogu kodu współużytkowanego, wskazywanego względem katalogu, który zawiera skrypt wywołujący: #! /bin/bash - AWK=${AWK:-nawk} $AWK -f `dirname $0`/../share/lib/myprog.awk -- $@ 9.3. Elementy programu | 255 Polecenie dirname było już opisywane w podrozdziale 8.2. Powyższy kod zakłada, że jeśli skrypt przechowywany jest na przykład w katalogu /usr/local/bin, wtedy plik kodu programu awk jest wyszukiwany w katalogu /usr/local/share/lib. Zastosowanie polecenia dirname gwa- rantuje poprawne wyszukiwanie pliku kodu awk dopóty, dopóki zachowana zostanie względna ścieżka pomiędzy plikiem skryptu a plikiem kodu programu awk. 9.3.7. Zmienne środowiskowe Z programu awk można odwoływać się do kompletu zmiennych środowiskowych powłoki odzwierciedlanych na czas wykonania programu w tablicy ENVIRON: $ awk BEGIN { print ENVIRON[ HOME ]; print ENVIRON[ USER ] } /home/janusz janusz Tablica ENVIRON nie wyróżnia się niczym szczególnym: można do niej dodawać elementy, modyfikować je i usuwać. Jednakże POSIX wymaga, aby podprocesy dziedziczyły środowi- sko, a w żadnych testowanych przez nas implementacjach zmiany wartości elementów tablicy ENVIRON nie były propagowane ani do podprocesów, ani do funkcji wbudowanych. W szcze- gólności oznacza to niemożność kontrolowania zachowań zależnych od schematu lokalizacji funkcji manipulujących ciągami znaków, jak tolower() — nie da się na czas jej wywołania zmienić bieżącego schematu przypisaniem do ENVIRON[ LC_ALL ]. Tablicę ENVIRON należa- łoby więc traktować jako niemodyfikowalną perspektywę środowiska, jego lokalną kopię. Wyborem schematu lokalizacji na potrzeby podprocesów można sterować za pośrednictwem stosownej zmiennej środowiskowej ustawianej w ciągu wywołania podprocesu. W ten sposób można z poziomu programu awk na przykład posortować wiersze pliku w oparciu o schemat lokalizacji dla języka hiszpańskiego: system( env LC_ALL=es_ES sort plik_we plik_wy ) Funkcja system() będzie opisywana w jednym z kolejnych podrozdziałów, w punkcie 9.7.8. 9.4. Rekordy i pola W każdej iteracji niejawnej pętli przeglądającej pliki wejściowe, która jest podstawą modelu programistycznego awk, przetwarzany jest pojedynczy rekord będący zwykle pojedynczym wierszem tekstu. Rekordy dzieli się z kolei na pola będące podciągami wierszy. 9.4.1. Separatory rekordów Rekordy to zazwyczaj pojedyncze wiersze tekstu rozdzielane znakami nowego wiersza; awk definiuje jednak rekordy ogólniej, na bazie specjalnego separatora rekordów określanego war- tością zmiennej RS. W tradycyjnej implementacji awk, tudzież wedle specyfikacji POSIX, zmienna RS musi być al- bo pojedynczym znakiem, na przykład znakiem nowego wiersza (to wartość domyślna RS), albo ciągiem pustym. W tym ostatnim przypadku stosowana jest specjalna interpretacja sepa- ratora rekordów: na rekordy składają się wtedy całe akapity tekstu, czyli grupy wierszy roz- dzielane jednym bądź kilkoma wierszami pustymi; puste wiersze na początku i końcu pliku są wtedy ignorowane. Pola w tak grupowanych rekordach są oddzielane znakami nowego wiersza albo dowolnym innym separatorem definiowanym wartością zmiennej FS. 256 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk W gawk i mawk model ten doczekał się istotnego rozszerzenia: RS może określać wyrażenie regularne i może wtedy obejmować więcej niż jeden znak. Ustawienie RS = + ustala w roli separatora rekordów znak plusa, ale już RS = :+ dopasowuje separator w postaci jednego bądź wielu sąsiadujących znaków dwukropka. Daje to możliwość zdecydowanie elastycz- niejszego wyodrębniania rekordów — kilka przykładów zastosowań wyrażeń regularnych w roli separatorów pól znajdzie się w podrozdziale 9.6. Jeśli separator pól jest wyrażeniem regularnym, to nie sposób wnioskować o tekście dopaso- wanym do wzorca separatora z samej zmiennej RS. W gawk przewidziano więc dodatkową zmienną wbudowaną RT, ustawianą po wczytaniu każdego rekordu na ciąg dopasowany do wzorca separatora (w mawk jej nie ma). Przy braku implementacji separatorów rekordów w formie wyrażeń regularnych symulowanie takiej możliwości nie jest proste, zwłaszcza jeśli takie wyrażenia miałyby dopasowywać ciągi przekraczające granice wierszy — wszak większość narzędzi uniksowych operuje właśnie wierszami. Można pokusić się o zastosowanie polecenia tr do zamiany znaku nowego wier- sza na inny, niewykorzystywany znak, scalając strumień danych wejściowych do postaci jed- nego gigantycznego wiersza. Wtedy mogą jednak ujawnić się rozmaite ograniczenia wynika- jące z niewystarczających rozmiarów buforów przydzielanych dla przetwarzanych wierszy w owych narzędziach. Na tym tle gawk, mawk i emacs wyróżniają się jako narzędzia nie narzuca- jące wierszowej orientacji przetwarzanych danych. 9.4.2. Separatory pól Pola w rekordzie są wyodrębniane przez dopasowanie bieżącego wyrażenia regularnego przy- pisanego do wbudowanej zmiennej FS, która pełni rolę separatora pól. Domyślna wartość FS to pojedyncza spacja, ale nie jest ona interpretowana dosłownie: sepa- rator domyślny obejmuje dowolną (niezerową) liczbę znaków odstępów (spacji, tabulacji); wy- odrębniane pola są „obierane” ze spacji poprzedzających i uzupełniających właściwą wartość pola. Stąd dla programu awk rekordy: alfa beta gamma alfa beta gamma są (przy założeniu domyślnego ustawienia FS) identyczne — oba składają się z trzech pól o wartościach alfa , beta i gamma . To szczególnie cenne, kiedy dane wejściowe są przy- gotowywane przez ludzi. Jeśli zachodzi potrzeba, aby pola były separowane dokładnie jednym znakiem spacji, należy wykonać przypisanie FS = [ ] . Przy tak określonym separatorze spacje poprzedzające i uzupełniające podciąg znaków drukowalnych wejdą do podciągu właściwej wartości pola. Można to sprawdzić na poniższych przykładach wykrywających w identycznym wierszu (roz- poczynającym się i kończącym parą spacji) wejściowym różne ilości pól: $ echo raz dwa trzy | awk -F { print NF : $0 } 3: raz dwa trzy $ echo raz dwa trzy | awk -F [ ] { print NF : $0 } 7: raz dwa trzy W drugim wywołaniu awk doliczył się siedmiu pól: , , raz , dwa , trzy , i . 9.4. Rekordy i pola | 257 Zmienna FS jest traktowana jak wyrażenie regularne tylko wtedy, kiedy zawiera więcej niż jeden znak. Ustawienie FS = . oznacza więc wybranie do roli separatora pól znaku kropki; nie jest to w żadnym razie interpretowane jako wyrażenie regularne dopasowujące dowolny znak. We współczesnych implementacjach awk dopuszcza się też puste wartości FS. Wtedy każdy znak stanowi osobne pole rekordu. Z kolei w starszych implementacjach przypisanie ciągu pustego do FS to rezygnacja z wyodrębniania pól — każdy rekord ma wtedy tylko jedno pole, rozciągające się na całość rekordu. POSIX mówi zaś jedynie, że zachowanie programu dla pustej wartości separatora pól jest nieokreślone. 9.4.3. Pola Pola bieżącego rekordu są w programie awk dostępne za pośrednictwem specjalnych symboli: $1, $2, $3, ..., $NF. Indeksy symboli nie muszą być literałami (stałymi) — mogą być obliczane dynamicznie; w takim przypadku będą w razie potrzeby obcinane do wartości całkowitych. Dla k równego 3 to zarówno $k, jak i $(1+2), $(27/9), $3.14159 jak i $ 3.14159 i wreszcie $3 będą odwołaniami do trzeciego pola bieżącego rekordu. Symbol $0 odnosi się do całego bieżącego rekordu wejściowego w postaci odczytanej ze stru- mienia wejściowego, po obcięciu znaków (podciągów) separatora rekordów. Odwołania do symboli o numerach spoza zakresu od 0 do NF nie są odwołaniami błędnymi. Dają one w wyniku ciągi puste i nie tworzą nowych pól — chyba że wykonane zostanie przypisanie wartości do takiego symbolu. Efekt odwołania z nieliczbowym indeksem pola jest zależny od implementacji. Odwołania do pól o numerach ujemnych we wszystkich testowanych imple- mentacjach prowokowały komunikaty o błędach krytycznych. POSIX zakłada w tej kwestii jedynie tyle, że odwołania do symboli z indeksami innymi niż dodatnie liczbowe indeksy pól dają efekt „nieokreślony”. Do pól, tak jak do zwykłych zmiennych, można przypisywać wartości. Na przykład przypi- sanie $1 = alef jest całkowicie dozwolone i poprawne, o ile pamięta się o jego efekcie ubocznym: jeśli potem nastąpi odwołanie do całego ciągu rekordu, zostanie on zmontowany z bieżących wartości pól, ale rolę separatora pól będzie przy montażu pełnić wartość wbudowa- nej zmiennej OFS (separator pól na wyjściu), która domyślnie zawiera pojedynczy znak spacji. 9.5. Wzorce i akcje Sedno, właściwą treść programu w języku awk stanowią pary wzorców i akcji. To dzięki ta- kiemu modelowi przetwarzania programy awk są tak zwarte i treściwe zarazem. 9.5.1. Wzorce Wzorce są konstruowane z wyrażeń ciągów i (lub) wyrażeń liczbowych. Kiedy zastosowane dla bieżącego rekordu wejściowego dają wartość niezerową (logiczna „prawda”), interpreter podejmie wykonanie skojarzonej ze wzorcem akcji. Jeśli wzorzec składa się jedynie z wyra- żenia regularnego, próba dopasowania obejmuje cały ciąg bieżącego rekordu — czyli tak, jakby zamiast /wyrażenie/ zapisać $0 ~ /wyrażenie/. Oto kilka przykładów ilustrujących stosowanie wzorców: 258 | Rozdział 9. Nieuzbrojony a niebezpieczny — awk NF == 0 wybiera rekordy puste NF 3 wybiera rekordy o co najmniej 4 polach NR 5 wybiera pierwsze cztery rekordy wejścia (FNR == 3) (FILENAME ~/[.][ch]$/) wybiera trzeci rekord pliku źródłowego (nagłówkowego) języka C $1 ~ /janusz/ wybiera rekordy z ciągiem janusz w pierwszym polu /[Xx][Mm][Ll]/ wybiera rekordy zawierające ciąg XML (bez względu na wielkość liter) $0 ~/[Xx][Mm][Ll]/ jak wyżej Elastyczność dopasowywania wzorców jest potęgowana możliwością stosowania przedziałów rekordów. Otóż dwa wyrażenia rozdzielane przecinkiem wybierają rekordy, począwszy od re- kordu dopasowanego do lewego wyrażenia, po (włącznie) rekord dopasowany do prawego wyrażenia. Jeśli zdarzy się, że dany rekord pasuje do obu wyrażeń wyrażenia przedziałowego, wzorzec dopasuje tylko ten jeden rekord. Przedziały są więc konstruowane nieco inaczej niż w edytorze sed, gdzie rekordu kończącego przedział szukało się wśród rekordów znajdują- cych się za rekordem otwierającym. Oto kilka przykładowych wzorców z przedziałami: (FNR == 3), (FNR == 10) dopasowuje rekordy od 3. do 10. w każdym z kolejnych plików wejściowych / [Hh][Tt][Mm][Ll] /, / /[Hh][Tt][Mm][Ll] / dopasowuje ciało dokumentu HTML /[aeiouy][aeiouy]/, /[^aeiouy][^aeiouy]/ dopasowuje ciąg zaczynający się parą samogłosek a kończący parą spółgłosek W obrębie akcji skojarzonej ze wzorcem BEGIN zmienne FILENAME, FNR, NF i NR są początkowo niezdefiniowane; odwołania do nich zwracają ciągi puste albo zera. Jeśli program składa się jedynie z instrukcji zgrupowanych w obrębie akcji wzorca BEGIN, przetwarzanie kończy się po wykonaniu ostatniej instrukcji z akcji wzorca BEGIN — interpre- ter nie podejmuje przetwarzania plików wejściowych. Na wejściu do pierwszej akcji wzorca END zmienna FILENAME zawiera nazwę ostatnio prze- tworzonego pliku, a zmienne FNR, NF i NR zachowują wartości obowiązujące dla ostatniego rekordu wejściowego. Odwołanie do $0 w akcji skojarzonej z END jest odwołaniem niepewnym — w gawk i mawk (ale już nie w nawk) symbol ten zachowuje ciąg ostatniego rekordu. A POSIX milczy w tej kwestii. 9.5.2. Akcje Znamy już większość elementów języka awk związanych z konstruowaniem wzorców, które wybierają rekordy do przetworzenia. Właściwe przetwarzanie rekordu podejmuje się w ob- rębie akcji kojarzonej opcjonalnie z takim wzorcem. Język awk za pośrednictwem szeregu typów instrukcji i struktur pozwala na konstruowanie niemal dowolnych programów. Jednak omówienie większości instrukcji zostanie odłożone do podrozdziału 9.7. Na razie — poza instrukcjami przypisania — będziemy rozważać jedy- nie instrukcję print. W najprostszej postaci instrukcja print oznacza żądanie wypisania ciągu bieżącego rekordu wejściowego ($0) na standardo
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Programowanie skryptów powłoki
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: