- 1/9 - Linux: potoki, przekierowania i inne operatory sterujące w przykładach Strumienie danych: stdin, stdout, sterr... 2 Przekierowanie standardowego strumienia wyjścia (stout) do pliku - operatory > i >>... 3 Przekierowanie strumienia wyjścia do innego programu - operator pipe (potoki)...3 Przekierowanie strumienia błędów do pliku operatory 2> i 2>>... 5 Przekierowanie strumienia błędów i strumienia wyjścia do jednego pliku - operator &>...6 Zmiana źródła danych przesyłanych na strumień wejścia - operator <... 6 Plik specjalnego przeznaczenia - /dev/null...7 Inne operatory sterujące - operatory && oraz ;... 7 Kontynuowanie wpisywania komendy w kolejnej linii operator \... 8 Autor: mgr inż. Mariusz Zalewski (http://mmm.wshe.lodz.pl/mzalewski) Katedra Sieci i Systemów Operacyjnych WSHE (http://ksiso.wshe.lodz.pl) Wersja dokumentu: 1.02 (z dnia 13 czerwca 2005 r.)
- 2/9 - Strumienie danych: stdin, stdout, sterr Każda informacja, którą otrzymujemy i możemy zinterpretować, jest rodzajem danych. Strony internetowe, czyli dane w postaci zapisanych plików formatu html, php, asp, jsp lub innych przesyłane są, zmieniane i analizowane po drodze od serwera do klienta przez co najmniej kilkanaście narzędzi sprzętowych i programowych. Dane te wędrują (przepływają) z jednego miejsca do kolejnego, aby w ostateczności ukazać się na ekranie monitora. We wspomnianym przykładzie, zawartość strony najpierw jest przesyłana z dysku twardego serwera do jego pamięci operacyjnej, gdzie następnie przetwarzana jest przez oprogramowanie serwera WWW, aby dalej przesłać ją przez sieć komputerową (kilkanaście urządzeń sieciowych) do komputera odbiorcy. Następnie, za pośrednictwem sprzętu odbiorcy, jego karty sieciowej, pamięci operacyjnej, systemu operacyjnego, przeglądarki internetowej i karty graficznej przesyłana jest na ekran monitora. Procedura jest więc długa i czasami skomplikowana. Taki przepływ danych w określonym kierunku (w określone miejsce) nazywamy strumieniem danych. W systemie Linux, jak w każdym innym systemie operacyjnym, można również spotkać strumienie przepływających danych. Najważniejsze trzy, które definiują przesył danych między programami nazwane są: 1. stdin strumień wejścia jest to miejsce, do którego przesyłane są wejściowe dane dla programu. Program otrzymuje tym kanałem informacje, aby je przetworzyć. Aby działanie edytora tekstu miało sens, należy na jego stdin przesłać dane w postaci pliku, który użytkownik chce edytować. Na standardowe wejście przesyła się również komendy sterujące w programach wymagających interaktywnego wpisywania znaków lub poleceń. Przykładem może być program nslookup, służący do testowania serwerów usługi DNS. Na jego standardowe wejście przesyłane są dane pochodzące z klawiatury komputera, które dalej analizowane są przez sam program. Za pomocą przekierowań można zmienić źródło danych przekazywanych na stdin. Przykładowo, zamiast używania klawiatury, można na wejście przesłać plik z treścią komend. 2. stout strumień wyjścia strumień ten opuszczają dane, które generuje program (są wynikiem jego działania). Dane pochodzące z tego strumienia najczęściej są wyświetlanie w konsoli, na ekranie monitora, inaczej opisując strumień stout skierowany jest domyślnie na konsolę. Efekt można zobaczyć uruchamiając jedną z podstawowych komend date. Wynik (aktualna data i godzina) można zobaczyć na ekranie monitora. Można jednak przekierować strumień wyjścia w inne miejsce do pliku lub do strumienia wejścia innego programu. W takich przypadkach
- 3/9 - data nie zostanie wyświetlona na ekranie, tylko będzie zapisana w pliku tekstowym lub przeanalizowana przez następny program jako dane wejściowe. 3. sterr strumień wyjścia błędów podobnie jak w stdout strumień ten opuszczają dane, które generuje program. Charakterystyczną cechą danych pochodzących z tego strumienia jest to, iż informują one o błędach, jakie program napotkał przy wykonywaniu swojego zadania. Przykładowo, jeśli wykonamy komendę zmiany katalogu (cd) i jako parametr podamy nieistniejący katalog, to program wyśle przez strumień wyjścia błędów (sterr) informację, że taki katalog nie istnieje. Domyślnie strumień błędów jest skierowany na konsolę (tak jak stout), czyli pośrednio również na ekran monitora. Dlatego też, o wszystkich błędach użytkownik jest informowany na bieżąco w trakcie wykonywania programu. Strumień wyjścia błędów, można przekierować, aby nie przesyłał informacji o błędach na ekran, tyko zapisywał w pliku. Strumienie wyjścia (stdout) strumień wyjścia błędów (stderr) zostały oddzielone, aby można było każdy z nich przekierować w inne miejsce. Przekierowanie standardowego strumienia wyjścia (stout) do pliku - operatory > i >> Aby wynik działania komendy date był zapisany w pliku aktualna-data bieżącego katalogu należy wykonać komendę: $ date > aktualna-data Jeśli plik aktualna-data był wcześniej utworzony w systemie i zawierał jakieś dane, to powyższa komenda skasuje poprzednią zawartość i zapisze aktualną datę. Aby nie usuwać danych znajdujących się w tym pliku, czyli dopisać informacje na jego końcu, należy użyć innego operatora: $ date >> aktualna-data Przekierowanie strumienia wyjścia do innego programu - operator pipe (potoki) Przekierowanie wyniku jednego programu na wejście innego programu polega na przesłaniu danych pochodzących ze standardowego wyjścia (stout) pierwszego programu na strumień wejścia (stdin) innego programu. Operator pipe, ze względu na swoje możliwości, jest najczęściej
- 4/9 - wykorzystywanym operatorem w systemu Linux podczas pracy w konsoli. Komenda $ cat /etc/passwd wyświetli na ekranie zawartość pliku /etc/passwd (przechowującego informacje o kontach użytkowników). Wykonując komendę: $ cat /etc/passwd grep mail na ekranie pojawią się tylko te linie z wyniku komendy cat /etc/passwd, które zawierają słowo mail podane w parametrze komendy grep. Wynik komendy cat (czyli zawartość pliku /etc/passwd) będzie przesyłany na wejście komendy grep, która przeanalizuje go pod kontem występowania linii z tekstem mail i wyświetli na ekranie: mail:x:8:8:mail:/var/mail:/bin/sh fetchmail:x:110:65534:/var/run/fetchmail:/bin/sh Można przetwarzać wyświetlane informacje dalej: $ cat /etc/passwd grep mail cut -f1 -d: Powyższa komenda, wcześniejsze przefiltrowane dane w postaci dwóch linii, analizuje przy pomocy komendy cut. Jej parametry mówią o tym, aby otrzymane dane przefiltrować i wyświetlić (wysłać na standardowe wyjście) tylko pierwszą kolumnę danych tekstowych -f1 (-fx, gdzie x oznacza numer kolumny), zakładając, że kolumny oddzielone są znakiem dwukropka -d: (-dz, gdzie z oznacza znak). W wyniku końcowym na ekranie pojawia się tylko lista nazw kont użytkowników (znajdujących się w pierwszej kolumnie): mail fetchmail Komenda $ cat /etc/passwd grep mail cut -f3 -d: wyświetli tylko trzecią kolumnę: 8 110 Często wynik komendy find jest bardzo długi. Aby wyświetlić go w przystępnej formie i analizować, można wynik przekierować na wejście komendy less: # find / -iname 'a*' less Komenda powyższa szuka w systemie wszystkich plików, których nazwy rozpoczynają się literą 'a',
- 5/9 - następnie wynik prześle do programu less. Aby opuścić program less należy nacisnąć klawisz q. Za pomocą komendy wc (ang. words count) można zliczać liczbę znaków, słów i linii w danych przesłanych na jej wejście. Komenda $ ls -la /etc wyświetli listę wszystkich plików (każdy w osobnej linii) i katalogów znajdujących się w katalogu /etc. Przekierowując wynik tej komendy na wejście komendy wc: $ ls -la /etc wc -l użytkownik uzyska odpowiedź, ile tych plików istnieje. Ściśle analizując otrzyma informację, ile linii (parametr -l) zawiera wynik komendy ls -la /etc. Przekierowanie strumienia błędów do pliku operatory 2> i 2>> Standardowy strumień błędów, tak jak standardowy strumień wyjścia, jest domyślnie przekierowany na konsolę. O wszystkich błędach użytkownik jest więc natychmiast powiadamiany. Dla przykładu, wykonanie poniższej komendy jako zwykły użytkownik (np. knoppix w dystrybucji Knoppix): $ find / -iname '*resolv*' > ~/wynik-poszukiwan spowoduje wyświetlenie na ekranie listy błędów, jakie napotkał program find podczas swojej pracy (błędy związane są z brakiem dostępu do pewnych katalogów). Proszę zwrócić uwagę, iż sam wynik poszukiwań będzie zapisany do innego pliku. Mimo tego, błędy są wyświetlane na ekranie, ponieważ korzystają z innego strumienia (sterr) skierowanego na konsolę. Można ten strumień przekierować do pliku: $ find / -iname '*resolv*' 2> ~/bledy-podczas-poszukiwan Jeśli w pliku bledy-podczas-poszukiwan wcześniej byłyby jakieś informacje, to zostaną one skasowane. Za pomocą operatora 2>>, zamiast kasować zawartość pliku, można na jego końcu dopisać dane pochodzące ze strumienia: $ find / -iname '*resolv*' 2>> ~/bledy-podczas-poszukiwan Wynik poszukiwań będzie przekierowany na ekran (stout), a błędy będą dopisywane do pliku o nazwie bledy-poczas-poszukiwan.
- 6/9 - Przy pomocy jednego polecenia można przekierować dwa strumienie do osobnych plików: $ find / -iname '*resolv*' > ~/wynik-poszukiwan 2> ~/bledy-podczas-poszukiwan Przekierowanie strumienia błędów i strumienia wyjścia do jednego pliku - operator &> Za pomocą jednego operatora można przekierować standardowy strumień wyjścia i strumień błędów do tego samego pliku: $ find / -iname '*resolv*' &> ~/wynik-poszukiwan-i-bledy Zmiana źródła danych przesyłanych na strumień wejścia - operator < Jak wspomniano we wstępie, w trakcie wykonywania programu, czasami należy podać mu instrukcje sterujące. Wracając do wspomnianego programu nslookup, aby sprawdzić jaki adres IP ma komputer o nazwie domenowej www.wshe.lodzl.pl należy wykonać następujące kroki: $ nslookup > www.wshe.lodz.pl Server: 194.42.116.194 Address: 194.42.116.194#53 Non-authoritative answer: Name: www.wshe.lodz.pl Address: 194.42.117.6 > exit $ Wyjaśnienie: po uruchomieniu nslookup pojawia się prompt tego programu (>) oczekujący komend sterujących. Wpisując nazwę domeny (www.wshe.lodz.pl) i potwierdzając enterem, program wyświetli uzyskane od serwera informacje. Aby wyjść z programu należy wywołać wewnętrzną komendę exit programu nslookup. Użytkownik musi w trakcie używania programu podawać komendy sterujące. Jeśli często korzysta z tego programu, aby uzyskać informację o adresie IP
- 7/9 - serwera wshe, może przykładowo przygotować plik tekstowy o nazwie szukaj o treści: www.wshe.lodz.pl exit Plik ten zawiera komendy sterujące dla programu nslookup (to, co użytkownik musiałby za każdym razem pisać na klawiaturze). Następnie, przekierowując ten plik na wejście komendy nslookup: $ nslookup < szukaj użytkownik otrzyma od razu odpowiedź bez konieczności wpisywania komend sterujących: Server: 194.42.116.194 Address: 194.42.116.194#53 Non-authoritative answer: Name: www.wshe.lodz.pl Address: 194.42.117.6 Plik specjalnego przeznaczenia - /dev/null Jest to plik, do którego przekierowywane są dane, które użytkownika nie interesują - nie chce ich wyświetlać na ekranie lub zapisywać do pliku. O pliku /dev/null można mówić, jak o czarnej dziurze, do której można przesłać dane, ale już nie można ich z niej wyciągnąć. Wywołując komendę: $ find / -iname '*resolv*' 2> /dev/null system wyszuka plików o zadanej nazwie i wyświetli je na ekranie. Błędy nie będą natomiast nigdzie wyświetlane ani zapisywane. Plik /dev/null istnieje w systemie Linux ze względu na to, że strumienie wyjścia zawsze muszą być gdzieś skierowane. Jeśli skierujemy je na /dev/null, oznacza to, że dane, które opuszczają ten strumień nie będą wyświetlone, zapisane, czy też analizowane przez inny program. Inne operatory sterujące - operatory && oraz ; Bardzo przydatnym operatorem jest &&, gdyż pozwala na warunkowe wykonanie kolejnej komendy w przypadku, gdy pierwsza zakończyła swoje działanie bez błędów. Dla przykładu, wykonanie poniższej komendy jako administrator: # find / -iname '*resolv*' && echo bez bledow
- 8/9 - wyświetli listę znalezionych plików z frazą resolv w nazwie, a następnie, na końcu, komenda echo wyświetli napis bez bledow (jeśli oczywiście find nie napotka błędów). Wykonanie tej komendy z prawami zwykłego użytkownika z pewnością wygenerowałoby błędy, ze względu na brak dostępu do pewnych katalogów. Dlatego też w przypadku wykonania komendy z poziomu zwykłego użytkownika: $ find / -iname '*resolv*' && echo bez bledow napis bez bledow z pewnością się nie ukaże. Operatora && można użyć w jednym poleceniu kilka razy: # mount /mnt/cdrom && cp /mnt/cdrom/plik ~/kopia-pliku && umount /mnt/cdrom Polecenie to montuje cdrom i jeśli się to uda wykonuję kopię pliku z cdromu a następnie (jeśli kopiowanie zakończy się bez błędów) odmontuje cdrom z systemu. Innym operatorem, który pozwala na wykonanie kilku komend w jednej linii jest ;. W przeciwieństwie do && kolejna komenda za znakiem ; wykona się niezależnie od tego, czy błędy w poprzedniej komendzie wystąpiły, czy nie: $ echo -n dzisiaj jest ; date +%D ; echo Zycze milego dnia! wyświetli na ekranie (niezależnie, czy w pierwszej komendzie wystąpi błąd, czy nie): Dzisiaj jest 04/12/05 Zycze milego dnia! Kontynuowanie wpisywania komendy w kolejnej linii operator \ Często zdarza się, że komenda jest tak długa, iż nie mieści się w jednej linijce. Aby kontynuować pisanie komendy w następnej linii, na końcu poprzedniej, dla czytelności, można umieścić znak \. Dla przykładu: $ find \ > /etc \ > -iname '*resolv*' jest równoznaczne z wykonaniem komendy: $ find /etc -iname '*resolv*' Przy korzystaniu z systemu nie ma konieczności korzystania ze znaku \ przy długich komendach. Jeśli zachodzi taka potrzeba i komenda jest bardzo długa, konsola automatycznie przesunie kursor
- 9/9 - do następnej linii (treść komendy można wpisywać dalej). Problem stanowi dokumentacja. Zapisanie długich poleceń, na przykład potoków, w kilku liniach bez jawnego określenia czy linia stanowi dalszy ciąg komendy z poprzedniej linii może wprowadzić w błąd czytelnika. Proszę zwrócić uwagę, iż przykłady opisywane w tym dokumencie mogą być czytelniejsze w następującej postaci: # mount /mnt/cdrom \ && cp /mnt/cdrom/plik ~/kopia-pliku \ && umount /mnt/cdrom $ cat /etc/passwd \ grep mail \ cut -f3 -d: Ze względu na przejrzystszą formę, bardzo często spotyka się w dokumentacji do programów zastosowanie operatora \. Czytelnik ma wtedy pewność, iż kolejna linia stanowi kontynuację polecenia z bieżącej linii tekstu.