Polecenia które pełnią rolę filtrów są często używane w mechanizmie potoków, który poznaliśmy w podrozdziale poprzednim. Odpowiednie użycie filtrów w połączeniu z potokiem (ewentualnie jego rozgałęzieniem wywoływanym przez polecenie tee ) umożliwia użytkownikowi wykonanie większości codziennych prac administratora systemu bez potrzeby pisania dodatkowych programów.
Poznanie struktury poleceń zbudowanych z filtrów i potoków jest niezbędne do dobrego opanowania systemu operacyjnego Linux.
Przypomnijmy, że potok jest ciągiem poleceń prostych lub złożonych, które są odseparowane od siebie przez znak | . Rezultat każdego polecenia – z wyjątkiem ostatniego – jest traktowane przez polecenie następne jako jego standardowe wejście. Innymi słowy - potok – jest mechanizmem komunikacji pomiędzy różnymi poleceniami, który im pozwala wymieniać między sobą dane i używając w nim filtrów możemy wykonywać prawie wszystkie operacje na plikach.
Jest charakterystyczne, że niektóre polecenia są dopasowywane do współpracy między sobą. I tak polecenie sort współpracuje zawsze lub prawie zawsze z poleceniem uniq. Należy podkreślić, że polecenie sort jest także dopasowane do współpracy z poleceniami grep cut i paste. Jest chyba dla każdego oczywiste, że bardziej wydajne jest umieszczenie w mechanizmie potoku polecenia sort po poleceniu grep lub cut, które szukają danych, z tego prostego powodu, że wtedy sortujemy tylko część wyselekcjonowanego pliku.
Jest to jeden z wielu przykładów. Niewątpliwie dopasowane do współpracy są także polecenia cut paste i join. Polecenie cut wycina z pliku pola które można połączyć używając polecenia paste lub join. Przypomnijmy raz jeszcze wygląd mechanizmu potoku, jak wiemy operator | łączy standardowe wyjście polecenia1 ze standardowym wyjściem polecenia2.
polecenie1 | polecenie2
Potok może być dłuższy i zawierać więcej niż dwa polecenia:
polecenie1 | polecenie2 | polecenie 3 | polecenie4 | polecenie5
W takim przypadku polecenia środkowe (polecenie2,3,4) muszą być filtrami. Jak widzimy struktura mechanizmu potoku dostosowana jest do zasad funkcjonowania filtrów. Często stosując filtry i potoki stosujemy także przekierowania, które polega na tym, że standardowe wejścia-wyjścia mogą być skierowane do pliku, Skierowanie standardowego wyjścia polega na wysłaniu tekstu wyświetlanego na ekranie do pliku.
Wszystkie standardowe wejścia-wyjścia każdego procesu można także skierować do odpowiednich plików i proces zamiast szukać informacji w sygnałach wysyłanych z klawiatury, będzie ich poszukiwał w odpowiednich plikach. Tak więc rezultat potoku złożonych z wielu poleceń skierowujemy do pliku. Mechanizm ten przy niektórych poleceniach jest konieczny. Przetestujmy teraz mechanizm potoków których poleceniami są filtry (ale nie tylko).
Użytkownik chciałby się dowiedzieć ile plików w katalogu /dev zaczyna się od literhd ? Ćwiczenie jest względnie proste pod warunkiem, że użytkownik wie gdzie w strukturze drzewa katalogowego znajduje się katalog /dev :
$ ls /dev/hd* | wc -l
Użytkownik chciałby się dowiedzieć jaki plik w jego repertuarze jest największy – jakie polecenia wykorzystać ? Przede wszystkim pierwszym poleceniem potoku będzie dobrze wam znane polecenie ls -l
$ ls –l | sort -n +4 | tail 1
Użytkownik często – szczególnie na koniec dnia pracy – chciałby wiedzieć jakie pliki tego dnia zostały zmodyfikowane. Załóżmy, że jest 10 lipca, w takim razie potok, który wyświetli tą informacje będzie wyglądał następujący:
$ ls -l | grep -n ‘Jul 10’
Już po tych trzech przykładach widzimy, że użytkownik musi znać struktury wyświetleń podstawowych poleceń Linuxa. Niewątpliwie najważniejszym poleceniem jest – wielokrotnie w kursie omawiane – polecenie ls. Stąd kładziemy nacisk na poznanie jego struktury.
Użytkownik chciałby wyświetlić na ekranie tylko informacje o tych którzy zapisują pliki w katalogu. W takim przypadku wydajemy polecenie, które jest potokiem:
$ ls –l | cut d” ” -f5
Aby to wykonać użytkownik musi wiedzieć, że pierwsze pole (informacji uzyskanej dzięki poleceniu ls -l) definiuje uprawnienia użytkownika, a czwarte liczbę linków.
Czy wiesz co wyświetli się na ekranie po wpisaniu następującego polecenia ?
$ ls -l | grep ”rwxr-xr-x” | more
Wydajność mechanizmu potoku, możemy docenić jeżeli np. będziemy chcieli policzyć liczbę użytkowników systemu którzy używają bash-shell
$ cat /etc/passwd | grep /bin/bash | wc –l
Polecenie cat wyświetla zawartość pliku /etc/passwd w którym zawarty jest opis wszystkich użytkowników. Filtr grep selekcjonuje wiersze w których znajduje się ciąg znaków /bin/bash. Filtr wc liczy liczbę wierszy wyselekcjonowanych przez filtr grep.
Częstym błędem – używając mechanizmu potoków i filtrów – jest nielogiczne umieszczenie w potoku poszczególnych poleceń. Załóżmy, że chcielibyśmy z pliku passwd wyselekcjonować użytkowników których katalogi domowe znajdują się w systemie plików linux1. Możemy dokonać tego najpierw sortując plik passwd, nastepnie wyszukania szukanej informacji a na koniec jej wycięcia:
$ sort -t: +0 -1 /etc/passwd | grep linux1 | cut -f1 -d:
Zauważmy, jednak, że w tym przypadku zmuszamy shell do sortowania całego pliku passwd i dopiero następnie wybierania szukanej informacji. Bardziej wydajnie – dlaczego ? - byłoby najpierw wybrać dane i dopiero potem je posortować.
$ grep linux1 /etc/passwd | cut -f1 -d: | sort
Ktoś może zauważyć, że różnica jest nieistotna bo i tak w efekcie uzyskujemy to co chcieliśmy. Jednak trzeba wziąć pod uwagę, że plik passwd liczy niewiele wierszy i w takim wypadku, jego sortowanie odbędzie się błyskawicznie. Co jednak się stanie, jeżeli przy identycznym problemie, plik będzie liczył setki tysięcy wierszy ? Sortowanie będzie musiało zarezerwować dużą ilość pamięci i czas jego wykonywania będzie trwał nie kilka minut lecz nawet godzinę lub więcej, utrudniając prace i spowalniając egzekucje innych programów.
Zakończmy ten rozdział przykładem ilustrującym potęgę i prostotę mechanizmu potoków w połączeniu z filtrami. Załóżmy, że chcemy z tekstu zawartego w pliku plik3 utworzyć słownik alfabetyczny wszystkich słów z których składa się tekst. Problem możemy rozwiązać dzieląc go na trzy etapy:
1. tr - dzieli tekst na słowa
2. sort - sortuje słowa w porządku alfabetycznym
3. uniq - znosi powtarzające się słowa
$ tr -cs ‘a-zA-Z‘ ‘\12’ < plik3 | sort | uniq > plk4
W przykładzie tym wykorzystaliśmy mechanizm potoków, przekierowań używając trzech filtrów tr sort uniq do rozwiązania dość skomplikowanego zadania.
Kurs Linux - Bash użycie filtrów