Zrozumieć powłokę tekstową - standardowy strumień wyjściowy
19.06.2010 14:09
Kilka pochlebnych komentarzy pod ostatnim wpisem przekonało mnie do rozwinięcia nieco tematu "śmierdzącej" konsoli. Pisał o tym roobal, później pisałem o tym również ja. Zarzucano mi jednak, że niewiele osób zrozumie coś z mojego tekstu, więc tym razem postaram się napisać trochę jak dziecku. Będzie może mniej fachowo ale bardziej zrozumiale. Moim celem jest udowodnienie Wam, że powłoka tekstowa wcale nie jest taka "śmierdząca", ale można to stwierdzić wyłącznie poznając ją bliżej. Dlatego chciałbym czytelnikom przybliżyć nieco charakterystyczne cechy języka programowania powłoki bash. Dlaczego bash? Bo jest najpopularniejszy, standardowy w każdej znanej mi dystrybucji Linuksa i możliwy do zainstalowania w każdym innym systemie operacyjnym - również w Windows.
Prawdopodobnie większość czytelników DP korzysta z systemu Windows. Wielu z nich może sobie nawet nie zdawać sprawy z tego, że interfejs który widzi przed sobą to powłoka explorer.exe. Ta jest obsługiwana myszką i jest to dla nich coś zupełnie normalnego. Ale Windows standardowo jest wyposażony jeszcze w powłokę tekstową cmd - gdzieniegdzie zwaną wierszem poleceń. Jej uruchomienie powoduje otwarcie okna konsoli, a oczom użytkownika ukaże się "znienawidzone" czarne tło i migający kursor. Powłoka ta służy oczywiście do uruchamiania programów, które nie mają interfejsu graficznego i dane wyjściowe wyświetlane są w formie tekstowej. Zatem z jakiego programu możemy skorzystać... hmmm... jest tu pewien problem, bo programów użytkowych po prostu nie ma. Dlatego właśnie użytkownicy Windows uważają, że konsola jest zła, bo jest zwyczajnie bezużyteczna. Ale uparcie szukamy i dowiadujemy się, że istnieje takie polecenie jak ping do diagnozowania połączeń sieciowych, którego na próżno szukać w "okienkach". Dlatego pośpiesznie wpisujemy
ping dobreprogramy.pl
i naszym oczom ukazują się przydatne informacje. Chciałbym Wam pokazać jakie, ale w konsoli tekstowej cmd nie działa metoda Copy'ego-Paste'a. Właściwie nawet nie wiem, czy w jakikolwiek sposób wynik polecenia da się jakoś zapisać. Więc zamykam okno i stwierdzam, że ta konsola mi się do niczego nie przyda.
W powłoce tekstowej w Unix'ach sprawa wygląda zupełnie inaczej. Tutaj mamy pełną kontrolę nad danymi wejściowymi i wyjściowymi, a jak to działa postaram się wyjaśnić poniżej na przykładzie powłoki bash i systemu Linux. Należy też pamiętać, że większość (jak nie wszystkie) z metod opisanych poniżej działa również w powłoce sh i innych. Zdaję sobie sprawę, że opisywane przeze mnie techniki to absolutne podstawy i dla niektórych mogą wydawać się wręcz śmieszne, ale z pewnością przydatne. W końcowej fazie cyklu artykułów, w oparciu o poznane techniki, napiszemy skrypt, za pomocą którego zrobimy coś bardzo zaawansowanego, ale będziemy stosować wyłącznie bardzo proste przekształcenia. Prawdopodobnie niektórym opadną wtedy szczęki, jak zobaczą ile da się napisać w czterech linijkach :)
Każdy proces uruchomiony w Linuksie jest połączony z terminalem za pomocą trzech standardowych strumieni. - STDIN - standardowy strumień wejściowy - to strumień, z którego program pobiera dane. Domyślnie jest to zawsze klawiatura. - STDOUT - standardowy strumień wyjściowy - tutaj kierowane są wyniki programu. Domyślnie jest to ekran. - STDERR - standardowy strumień błędów - tutaj kierowane są wszystkie informacje o błędach. Domyślnie jest to ekran.
Dziś skupimy się na STDOUT.
Oprogramowanie nie jest nic warte, jeżeli nie generuje pewnego rodzaju danych wyjściowych. Ale z doświadczenia wiemy, że mamy wiele typów tych danych, które muszą być zapisywane na różnych rodzajach pamięci. Wyświetlanie czegokolwiek na ekranie różni się znacznie od zapisu określonej treści w pliku czy karcie pamięci (przynajmniej z pozoru). Dlatego jednym z podstawowych założeń systemu operacyjnego Unix (a co za tym idzie i Linux) jest zagwarantowanie możliwości traktowania każdego elementu jako pliku. Odpowiedzialnością za udostępnienie takiego mechanizmu został obarczony system operacyjny. Zatem bez znaczenia stało się to, czy dane są przekazywane są do pliku dyskowego, terminala, karty pamięci czy innego urządzenia.
Jak to działa postaram się przedstawić za pomocą prostego polecenia echo. Jego zadaniem jest wyświetlenie wpisanego tekstu, np.
chomik@zhp:~$ echo dobreprogramy.pl to moja ulubiona strona internetowa dobreprogramy.pl to moja ulubiona strona internetowa
Jak widać powyżej efektem polecenia jest wyświetlenie w terminalu zdania "dobreprogramy.pl to moja ulubiona strona internetowa". Z technicznego punktu widzenia wspomniane zdanie zostało przekazane do standardowego strumienia wyjściowego polecenia echo, czyli zostało wyświetlone na ekranie. Jednak tutaj, w przeciwieństwie do powłoki cmd, domyślny STDUOT można zmienić za pomocą odpowiednich operatorów. Najprostszym i chyba najczęściej używanym jest operator przekierowania ">". Przekierujmy zatem nasze zdanie do pliku plik.txt.
chomik@zhp:~$ echo dobreprogramy.pl to moja ulubiona strona internetowa > plik.txt chomik@zhp:~$
Tym razem nasze zdanie nie zostało wyświetlone na ekranie, bo za pomocą operatora ">" przekierowaliśmy standardowy strumień wyjściowy do pliku plik.txt. Zatem sprawdźmy, czy nasz tekst rzeczywiście tam jest za pomocą instrukcji cat, której zadaniem jest wyświetlenie zawartości pliku na ekranie.
chomik@zhp:~$ cat plik.txt dobreprogramy.pl to moja ulubiona strona internetowa chomik@zhp:~$
Tekst oczywiście tam jest. Tą samą metodę możemy zastosować do każdego innego polecenie. Teraz już mogę Wam pokazać wynik polecenia ping, co próbowałem zrobić wcześniej, bo teraz mogę bez problemu te dane skopiować, ale również mogę je zapisać do pliku. Zatem:
chomik@zhp:~$ ping -c 2 dobreprogramy.pl > plik.txt chomik@zhp:~$ chomik@zhp:~$ cat plik.txt 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=122 time=28.0 ms 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=122 time=28.0 ms (DUP!) 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=122 time=28.0 ms (DUP!) 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=2 ttl=122 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/28.000/28.000/0.000 ms chomik@zhp:~$
Teraz w pliku plik.txt mamy wynik polecenia ping. Uważni zauważą jednak, że z naszego pliku zniknęło zdanie, że DB to nasza ulubiona strona. Stało się tak, że operator ">" zawsze nadpisuje plik. Jeżeli go nie ma to go tworzy, jeżeli jest to usuwa i tworzy z nową treścią. Żeby tego uniknąć to należy skorzystać z operatora dopisania ">>", którego zdaniem jest dopisywanie treści na koniec pliku. Zatem przykład:
chomik@zhp:~$ echo dobreprogramy.pl to moja ulubiona strona internetowa > plik.txt chomik@zhp:~$ ping -c 2 dobreprogramy.pl >> plik.txt chomik@zhp:~$ chomik@zhp:~$ cat plik.txt dobreprogramy.pl to moja ulubiona strona internetowa 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=122 time=36.0 ms 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=122 time=36.0 ms (DUP!) 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=1 ttl=122 time=36.0 ms (DUP!) 64 bytes from nlb-web.xenium.pl (194.0.171.150): icmp_seq=2 ttl=122 time=32.0 ms --- dobreprogramy.pl ping statistics --- 2 packets transmitted, 2 received, +2 duplicates, 0% packet loss, time 1004ms rtt min/avg/max/mdev = 32.000/35.000/36.000/1.732 ms chomik@zhp:~$
To chyba już nie wymaga komentarza.
Podsumowanie
W tym wpisie poznaliśmy prosty mechanizm, który pozwala nam na przekierowanie standardowego strumienia wyjściowego. Należy pamiętać, że w Linuksie poleceń w konsoli jest tysiące, każde z nich ma wiele parametrów, ale wynik ich wszystkich można zapisać dokładnie w ten sam sposób. Te same dane można wykorzystać w celu dalszej obróbki, ale o tym będzie w następnym wpisie.