Zrozumieć powłokę tekstową - niezwykła moc potoków
System Linux i każdy UNIX ma jedną, wielką zaletę, o której pisałem już w poprzednich wpisach. Otóż większość plików, które mają znaczenie administracyjne, to proste pliki tekstowe nadające się do edycji bez pomocy specjalizowanych narzędzi. Wystarczy prosty edytor tekstu, jak np. notatnik. Wszystkie pliki konfiguracyjne znajdują się w katalogu /etc, w którym każdy program ma własny katalog z plikami konfiguracyjnymi. Pliki te, tak jak już wcześniej wspomniałem, pisane są otwartym tekstem.
Ale jaki to ma związek z potokami? Skoro cała konfiguracja systemu to pliki tekstowe, a powłoka bash i system Linux zawierają wiele narzędzi do ich edycji, tzn. że z poziomu terminala jesteśmy w stanie zrobić dosłownie wszystko. W poprzednich artykułach pisałem już o strumieniach (STDOUT, STDIN, STDERR ). Ich znajomość pozwala nam na odpowiednie skierowanie danych wejściowych i wyjściowych wszystkich programów. Ale czy da się wykorzystać dane wyjściowe programu A jako dane wejściowe programu B? Ależ oczywiście, że TAK. I jaka w tym niezwykła moc? - czytajcie dalej.
Operator potoku "|" jest niezwykły. Potrafi przekierować STDOUT jednego programu do STDIN drugiego bez konieczności zapisywanie w międzyczasie jakikolwiek plików czy zmiennych. Zamiast rozpisywać się na jego temat pokażmy jak działa. Zatem wracamy do naszego pliku plik.txt i tym razem zaszalejmy i dodajmy do niego dwie linie tekstu.
echo dobreprogramy.pl to moja ulubiona strona internetowa > plik.txt echo HotZlot to najlepsza impreza IT >> plik.txt
(pomijam fakt, że te dwie linie można dodać jednym poleceniem, ale nie chcę robić początkującym wody z mózgu)
Zanim jednak skorzystamy z operatora potoku, to musimy ustalić co z tym tekstem chcemy zrobić. Dlatego muszę czytelnikom przybliżyć kila narzędzi. Zaczniemy od grep
grep - bardzo proste narzędzie, którego zadaniem jest wyszukiwanie w tekście określonego ciągu znaków (obsługuje wyrażenia regularne), a wynikiem jego działania najczęściej jest wiersz z tekstu zawierający wyszukiwaną frazę.
Zatem wyszukajmy w naszym pliku słowa HotZlot:
chomik@zhp:~$ cat plik.txt | grep HotZlot HotZlot to najlepsza impreza IT
Jak widać najpierw za pomocą polecenia cat postanowiliśmy wyświetlić zawartość pliku plik.txt. Następnie STDOUT polecenia cat został za pomocą operatora potoku "|" skierowany bezpośrednio na STDIN polecenia grep, którego zadaniem jest wyszukanie frazy HotZlot. W wyniku mamy tylko wiersz zawierający szukane słowo.
Na pierwszy rzut oka do niczego nam się to nie przyda, ale jak poznamy np. narzędzie cut to zaczyna się robić ciekawiej.
cut - narzędzie służące do wyłuskiwania potrzebnych danych z wiersza. A zasadę jego działania wytłumaczę na przykładzie polecenia ping.
chomik@zhp:~$ ping -c 2 dobreprogramy.pl PING dobreprogramy.pl (194.0.171.150) 56(84) bytes of data. 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=121 time=32.0 ms 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=121 time=32.0 ms (DUP!) 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=121 time=32.0 ms (DUP!) 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=2 ttl=121 time=28.0 ms --- dobreprogramy.pl ping statistics --- 2 packets transmitted, 2 received, +2 duplicates, 0% packet loss, time 1004ms rtt min/avg/max/mdev = 28.000/31.000/32.000/1.732 ms
Załóżmy, że do naszego skryptu potrzebujemy pobrać dane o średnim czasie odpowiedzi danego serwera - w tym wypadku dobreprogramy.pl. To ta podkreślona wartość wyświetlona w ostatniej linii.
rtt min/avg/max/mdev = 28.000/31.000/32.000/1.732 ms
Będziemy to robić dziennie tysiąc razy, więc ręczne przepisywanie nie wchodzi w grę. Jak to wyłuskać? Najpierw z wyniku naszego polecenia ping bierzemy tylko ostatnią linię. Łatwo ją wydobyć poleceniem grep bo zawsze w niej znajduje się słowo rtt (round trip time).
chomik@zhp:~$ ping -c 2 dobreprogramy.pl | grep rtt rtt min/avg/max/mdev = 28.000/31.000/32.000/1.732 ms
Teraz zastosujemy magię polecenia cut. Żeby wydobyć interesujące nas dane, musimy powiedzieć komputerowi jak ma je znaleźć. Można to zrobić za pomocą znaków separatora pól. Pomiędzy słowami są znaki spacji. Teraz wystarczy powiedzieć powłoce po którym znaku spacji są interesujące nas dane. Wyobraźmy sobie, że każdy tekst pomiędzy znakami spacji to kolumna. W takim razie w pierwszej kolumnie będzie "rtt", w drugiej "min/avg/max/mdev", w trzeciej "=", a w czwartej "28.000/31.000/32.000/1.732". Zatem możemy zawęzić wynik tylko do czwartej kolumny.
chomik@zhp:~$ ping -c 2 dobreprogramy.pl | grep rtt | cut -d' ' -f4 28.000/31.000/32.000/1.732
Czyli tak: 1. ping ping -c 2 dobreprogramy.pl - wykonuje polecenie 2. grep rtt - wycina ostatnią linie wyniku 3. cut -d' ' -f4 - wycina czwartą kolumnę. Przełącznikiem "‑d" definiujemy separator pola - tutaj jest to spacja; a "‑f" definiuje numer kolumny
Ale nas dalej interesuje tylko to 31.000, więc potok puszczamy dalej i znów skorzystajmy z polecenia cut, ale tym razem jako separator pola użyjemy znaku "/".
chomik@zhp:~$ ping -c 2 dobreprogramy.pl | grep rtt | cut -d' ' -f4 | cut -d'/' -f2 31.000
Teraz wynikiem jest interesująca nas liczba. Możemy ją zapisać do zmiennej, do pliku, lub przekierować gdzieś dalej.
Teraz pewnie połowa z Was zachodzi w głowę do czego to się może przydać. Ja nie lubię podawać gotowego rozwiązania na tacy, dlatego drodzy młodzi administratorzy dostaniecie ode mnie zadanie, aby w komentarzu opisać co będzie wynikiem poniższego polecenia i co dzięki temu możemy uzyskać. Potrzebujecie do tego Linuksa (Ubuntu, bo w innych dystrybucjach plik z logami może mieć inną nazwę), powłokę bash, uprawnienia administratora lub prawo do odczytania pliku /var/log/auth.log.
cat /var/log/auth.log | grep 'Failed password for root' | cut -d' ' -f12 | uniq
Przestrzegam, że nieświadome uruchamianie tego polecenia może Wam coś popsuć, dlatego robicie to na własną odpowiedzialność.