[ Pobierz całość w formacie PDF ]
pisania rekordów z wejścia na wyjście.
W ogólniejszym przypadku instrukcji print może towarzyszyć lista zera bądz większej liczby
wyrażeń oddzielanych przecinkami. Każde z tych wyrażeń podlega wartościowaniu, ewen-
tualnej konwersji na ciąg znaków, a następnie jest wypisywane na standardowym wyjściu.
Kolejne elementy listy są na wyjściu oddzielane wartością separatora pól wyjściowych
OFS. Ostatni element jest uzupełniony ciągiem separatora rekordów wyjściowych OSR.
Lista argumentów instrukcji print (a także instrukcji printf i sprintf, zobacz punkt 9.9.8)
może być ujęta w nawiasy. Zastosowanie nawiasów eliminuje ewentualne niejednoznaczno-
ści przy przetwarzaniu listy argumentów, jeśli ta zawiera np. operatory relacji symbole
reprezentujące te operatory, czyli , są bowiem wykorzystywane również w roli operato-
rów przekierowania wejścia-wyjścia (patrz punkty 9.7.6 i 9.7.7).
Pora na kilka przykładów kompletnych programów języka awk. Każdy z nich wypisuje na
wyjściu wartości pierwszych trzech pól; brak określenia wzorca wyboru rekordu powoduje
przetworzenie wszystkich rekordów wejściowych. Zredniki oddzielają kolejne instrukcje pro-
gramu języka awk. Efekt działania programów jest różnicowany zmianami separatora pól
wyjściowych:
$ echo 'raz dwa trzy cztery' | awk '{ print $1, $2, $3 }'
raz dwa trzy
$ echo 'raz dwa trzy cztery' | awk '{ OFS = "..."; print $1, $2, $3 }'
raz...dwa...trzy
$ echo 'raz dwa trzy cztery' | awk '{ OFS = "\n"; print $1, $2, $3 }'
raz
dwa
trzy
Zmiana separatora pól wyjściowych, jeśli po niej nie nastąpi przypisanie wartości do któregoś
z pól, nie modyfikuje ciągu $0:
$ echo 'raz dwa trzy cztery' | awk '{ OFS = "\n"; print $0 }'
raz dwa trzy cztery
Gdybyśmy jednak zmienili separator pól wyjściowych, a potem przypisali nową wartość do
jednego (dowolnego) z pól, to nawet gdyby przypisanie faktycznie nie zmieniło wartości
pola, interpreter dokonałby ponownego montażu $0 z uwzględnieniem nowej wartości sepa-
ratora pól:
$ echo 'raz dwa trzy cztery' | awk '{ OFS = "\n"; $1 = $1; print $0 }'
raz
dwa
trzy
cztery
9.6. Jednowierszowce w awk
Znamy już awk na tyle, aby skutecznie konstruować krótkie, jednowierszowe programy. Ma-
ło który język pozwala na tak wiele przy tak krótkim kodzie. Przyjrzymy się więc kilku jed-
nowierszowcom, choć niektóre z nich ze względu na ograniczenia składu zostaną rozbite
260 | Rozdział 9. Nieuzbrojony a niebezpieczny awk
na kilka wierszy. W niektórych z tych przykładów postawione zadanie będzie rozwiązywane
na kilka sposobów, z użyciem awk i alternatywnie, za pomocą innych standardowych narzędzi
uniksowych.
" Na początek prosta implementacja (w awk) popularnego uniksowego narzędzia zliczającego
słowa wc:
awk '{ C += length($0) + 1; W += NF } END { print NR, W, C }'
Zauważ, że grupy wzorzec-akcja nie muszą być oddzielane znakami nowego wiersza,
choć zwykle stosuje się je dla zwiększenia czytelności kodu. Skoro awk nie wymaga de-
klarowania i wstępnej inicjalizacji zmiennych, blok BEGIN { C = W = 0 }, choć nie za-
szkodziłby, jest zbędny. Licznik znaków wejścia, przechowywany w zmiennej C, jest przy
każdym rekordzie zwiększany o rozmiar tegoż rekordu i dodatkowo jeden znak, który
reprezentuje wycięty z ciągu rekordu znak nowego wiersza. Licznik słów (W) zlicza liczbę
pól w kolejnych wierszach. Licznik wierszy jest niepotrzebny, bo jego rolę z powodzeniem
pełni wbudowana zmienna licznika rekordów, NR. Jednowierszowe zestawienie, podobne
do tego generowanego przez wc, wypisuje akcja skojarzona z wzorcem END.
" Jeśli program jest pusty, awk kończy działanie bez wczytywania wejścia, może więc ry-
walizować z systemową czeluścią /dev/null:
$ time cat *.xml > /dev/null
0.035u 0.121s 0:00.21 71.4% 0+0k 0+0io 99pf+0w
$ time awk '' *.xml
0.136u 0.051s 0:00.21 85.7% 0+0k 0+0io 140pf+0w
Poza pewnymi problemami związanymi z obsługą znaków pustych awk może z powo-
dzeniem emulować polecenie cat, jak tu, gdzie oba polecenia dają identyczny efekt:
cat *.xml
awk 1 *.xml
" W awk można łatwo uzupełnić kolumnę wartości liczbowych kolumną ich logarytmów:
awk '{ print $1, log($1) }' plik(i)
" Problemem nie jest też wypisanie losowo dobranej próbki obejmującej 5% wierszy plików
tekstowych (przy użyciu funkcji generatora liczb pseudolosowych patrz podrozdział 9.10
dającej równomierny rozkład losowanych wartości pomiędzy 0 a 1):
awk 'rand()
" Aatwo wypisać sumę wartości n-tej kolumny w tabeli z kolumnami oddzielanymi zna-
kami odstępów:
awk -v COLUMN=n '{ sum += $COLUMN } END { print sum }' plik(i)
" Po drobnej modyfikacji otrzymujemy program liczący średnią wartość n-tej kolumny:
awk -v COLUMN=n '{ sum += $COLUMN } END { print sum / NR }' plik(i)
" Wypisanie łącznej kwoty wydatków zapisywanych w plikach, które zawierają rekordy
składające się z opisu pozycji wydatku i kwoty wydatku w ostatnim polu, sprowadza się
do odpowiedniego wykorzystania wbudowanej zmiennej NF:
awk '{ sum += $NF; print $0, sum }' plik(i)
" A tak można wyszukiwać ciągi w plikach tekstowych:
[ Pobierz całość w formacie PDF ]