Przetwarzanie plików tekstowych

Podczas lekcji trzeciej zapoznaliśmy się z kilkoma poleceniami do przeglądania plików tekstowych. Oprócz nich w Unixie istnieje duży zbiór poleceń wybierania i modyfikowania zawartości plików. Polecenia te umożliwiają w bardzo wielu przypadkach uzyskanie żądanych wyników bez potrzeby programowania.

Filtry znakowe

Proste operacje zamiany i usuwania znaków można wykonać nie korzystając z edytora. Chcąc zamienić wszystkie występujące w tekście małe litery na duże, możemy użyć poznanego już polecenia tr.

$ cat przybysze
Kangurzyca
Maleństwo
Tygrys
$ tr "aąbcćdeęfghijklłmnńoópqrsśtuvwxyzźż" \
> "AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ" <przybysze
KANGURZYCA
MALEŃSTWO
TYGRYS
$ _

Argumentami polecenia tr są dwa ciągi znaków, najlepiej tej samej długości. Zostały one ujęte w cudzysłowy. Polecenie czyta tekst ze standardowego wejścia. Po napotkaniu w tekście znaku występującego w pierwszym ciągu zastępuje go odpowiadającym mu znakiem z drugiego ciągu. Tak zmodyfikowany tekst wypisywany jest na standardowe wyjście.

Działanie programu tr polega więc na przesyłaniu danych ze standardowego wejścia na standardowe wyjście, z równoczesnym dokonywaniem wskazanych zmian. W naszym przykładzie standardowym wyjściem był ekran, natomiast wejście zostało przeadresowane na plik przybysze. Ten sposób pracy, charakterystyczny dla wielu poleceń Unixa, przypomina filtrowanie danych, dlatego programy takie nazywa się filtrami.

Przy zapisywania ciągów znaków można stosować klasy znaków.

$ tr "[a-ż]" "[A-Ż]" <przybysze >duże
$ cat duże
KANGURZYCA
MALEŃSTWO
TYGRYS
$_

Polecenie tr ma kilka wariantów wybieranych opcjami, służących do pomijania wybranych znaków (czyli do zmiany ,,sposobu filtracji''). Używany jest wtedy tylko jeden argument. Opcja -d powoduje pominięcie wszystkich znaków występujących w argumencie. Nie są one wysyłane na standardowe wyjście.

$ tr -d "aąeęioóuy" <przybysze
Kngrzc
Mlństw
Tgrs
$ _

Pozbyliśmy się wszystkich samogłosek. Trudniej jest pozbyć się znaków końca linii. Skorzystamy z opcji -c.

$ tr -cd "bcćdfghjklłmnńpqrsśtvwxzźż" <przybysze
KngrzcMlństwTgrs
$ _

Opcja ta zmienia działanie opcji -d, powodując pomijanie wszelkich znaków poza wskazanymi argumentem. Przy okazji poznaliśmy skrótowy sposób zapisywania kilku jednoliterowych opcji.

Potoki

Usuwanie samogłosek przydaje się nie tylko na kursach Unixa. Może posłużyć do statystycznego badania tekstów, na przykład zliczania występujących w nich samogłosek i spółgłosek. Potrzebne będzie do tego jeszcze polecenie wc.

$ cat postacie
Krzyś
Kubuś Puchatek
Prosiaczek
Kłapouchy
Królik
Sowa Przemądrzała
$ wc postacie
     6     8     67     postacie
$ _

Polecenie wc (od ang. word count) wypisuje liczbę linii, słów i znaków w podanym pliku. Zwróćmy uwagę, że znaki końca linii są również liczone.

Czasem jednak interesuje nas tylko jedna z tych informacji. Wyboru możemy dokonać używając opcji. Opcja często wybiera tylko część działania polecenia, na przykład polecenie wc z opcją -l zlicza tylko linie, z opcją -w (ang. word) tylko słowa, zaś z opcją -c (ang. characters) tylko znaki.

$ wc -l postacie
6
$ wc -w postacie
8
$ wc -c postacie
67
$ _

Możemy już teraz policzyć spółgłoski. Potrzebny nam będzie pomocniczy plik roboczy.

$ tr -cd "bcćdfghjklłmnńpqrsśtvwxzźż" <przybysze >spółgłoski
$ cat spółgłoski
KngrzcMlństwTgrs
$ wc -c spółgłoski
16
$ rm spółgłoski
$ _

Użyta metoda była skuteczna, ale niezbyt elegancka. Musieliśmy skorzystać z pliku pośredniego.

Ponieważ łączenie filtrów jest często stosowane, Unix posiada do tego specjalny mechanizm, pozwalający unikać stosowania plików pośrednich. Nazywany jest on potokiem. Dwa polecenia łączymy w potok zapisując je obok siebie i oddzielając kreską pionową. Powoduje to powiązanie standardowego wyjścia pierwszego potoku ze standardowym wejściem drugiego.

$ tr -cd "bcćdfghjklłmnńpqrsśtvwxzźż" <przybysze | wc -c
16
$ _

I to wszystko. Niepotrzebny jest plik pośredni. Skorzystaliśmy z tego, że polecenie wc w razie braku argumentu czyta ze standardowego wejścia.

Policzmy teraz pliki w naszym katalogu. Znowu przyda się do tego potok.

$ ls
duże
postacie
przybysze
wszyscy
$ ls | wc -l
4
$ _
Każdego, kto zaczyna poznawać system Unix, razi trochę zwięzłość ,,wypowiedzi'' większości jego poleceń. Wytłumaczenie uzyskaliśmy powyżej. Użycie przez polecenie ls dodatkowych nagłówków czy ozdobników przy wypisywaniu zwiększyłoby raczej w niewielkim stopniu czytelność, natomiast uniemożliwiłoby umieszczanie tego polecenia w potokach.

Sortowanie

Obejrzyjmy teraz zawartość pliku postacie w porządku alfabetycznym.

$ sort postacie
Kłapouchy
Królik
Krzyś
Kubuś Puchatek
Prosiaczek
Sowa Przemądrzała
$ _

Polecenie sort zgodnie z nazwą sortuje zawartość podanego pliku w kolejności alfebetycznej i wypisuje posortowaną zawartość na standardowe wyjście. Nie zmienia ono zawartości pliku wejściowego.

Jeśli użyjemy przeadresowania, to posortowaną treść możemy zapamiętać na innym pliku.

$ sort -r postacie >po.kolei
$ ls
postacie
po.kolei
przybysze
wszyscy
$ cat po.kolei
Sowa Przemądrzała
Prosiaczek
Kubuś Puchatek
Krzyś
Królik
Kłapouchy
$ _

Opcja -r (od ang. reverse) powoduje, że sortowanie dokonywane jest w odwrotnej kolejności.

Proste tabele

Korzystając z poleceń Unixa łatwo bez używania oprogramowania baz danych obsługiwać proste tabele. Załóżmy, że naszą (posortowaną) listę postaci uzupełniliśmy informacją o ich przynależności gatunkowej i rozmiarach.

$ cat wszyscy
Kangurzyca        kangur     duże
Kłapouchy         osiołek    duże
Królik            królik     duże
Krzyś             chłopiec   duże
Kubuś Puchatek    miś        duże
Maleństwo         kangur     małe
Prosiaczek        prosiaczek małe
Sowa Przemądrzała sowa       duże
Tygrys            tygrys     duże
$ _

Aby wypisać wyłącznie listę postaci, należy użyć polecenia cut.

$ cut -c1-18 wszyscy
Kangurzyca        
Kłapouchy         
Królik            
Krzyś             
Kubuś Puchatek    
Maleństwo         
Prosiaczek        
Sowa Przemądrzała 
Tygrys            
$ _

Wymaga ono opcji podającej pozycje (w ramach wiersza) znaków, które chcemy wyciąć. Myślnik pozwala zapisywać zakresy pozycji. Pozycje (bądź ich zakresy) oddzielamy przecinkami.

Możemy także wypisać postacie wraz z informacją o ich rozmiarach.

$ cut -c1-18,30-33 wszyscy
Kangurzyca        duże
Kłapouchy         duże
Królik            duże
Krzyś             duże
Kubuś Puchatek    duże
Maleństwo         małe
Prosiaczek        małe
Sowa Przemądrzała duże
Tygrys            duże
$ _

Zbadajmy teraz, jakie gatunki występują na naszej liście.

$ cut -c19-29 wszyscy
kangur     
osiołek    
królik     
chłopiec   
miś        
kangur     
prosiaczek 
sowa       
tygrys
$ _

Jeden z gatunków wystąpił dwukrotnie. Wolelibyśmy, aby takie duplikaty były automatycznie usuwane. Aby to zrobic, musimy najpierw posortować otrzymaną listę.

$ cut -c19-29 wszyscy | sort
chłopiec
kangur
kangur
królik
miś
osiołek
prosiaczek
sowa
tygrys
$ _

Możemy już teraz posłużyć się filtrem uniq. Polecenie to usuwa powtarzające się linie (ale tylko gdy występują obok siebie, dlatego musieliśmy najpierw posortować).

$ cut -c19-29 wszyscy | sort | uniq
chłopiec
kangur
królik
miś
osiołek
prosiaczek
sowa
tygrys
$ _

Aby otrzymać tylko informację o liczbie różnych gatunków, wystarczy na koniec potoku dołożyć jeszcze jeden filtr.

$ cut -c19-29 wszyscy | sort | uniq | wc -l
8
$ _

Używając poznanych poleceń i potoków możemy wyciąc z tabeli odpowiedni prostokąt (np. pola 3 i 4 dla wierszy 1-3).

$ head -3 wszyscy | tail -5 | cut -f3,4 -d '*'
Kangurzyca        kangur     duże
Kłapouchy         osiołek    duże
Królik            królik     duże
$ _

Poznaliśmy tylko niewielką część poleceń służących do przetwarzania tekstów. Ważniejsza od znajomości ich pełnego repertuaru jest umiejętność ich łączenia.