Podstawy pracy z interpreterem poleceń


Streszczenie

W wykładzie 2 przedstawiono interpreter poleceń, tzn. narzędzie, które pośredniczy w kontaktach między użytkownikiem i systemem operacyjnym. Interpreter poleceń czeka na zlecenia użytkownika i przekazuje je systemowi operacyjnemu. Potrafi obsłużyć nie tylko proste wykonanie programów, ale także bardziej złożone instrukcje sterujące. W tym wykładzie nauczymy się posługiwać interpreterem oraz pisać skrypty poleceń interpretera.

Istnieje wiele tego typu programów (najstarszy Bourne-shell, młodszy C-shell etc.). W trakcie tego wykładu przedstawimy interpreter bash.


Wstęp

Proponujemy czytelnikowi, aby na bieżąco wykonywał ćwiczenia dotyczące konstrukcji prezentowanych na wykładzie.

Można to robić na swoim komputerze lub na zdalnym serwerze. Jeśli mamy zainstalowany system Linux, to sprawa jest oczywista (wystarczy włączyć terminal). Jeśli zaś pracujemy na systemie Windows, to możemy podłączyć się do zdalnego serwera z systemem Linux lub zainstalować program o nazwie Cygwin, którego uruchomienie otworzy nam linuxową konsolę na systemie Windows.


Podłączenie do zdalnego serwera

Serwer ssh

Od 26.09.2005 jest dostępny dla studentów serwer shell pod adresem mushelka.pjwstk.edu.pl. Więcej na ten temat można przeczytać na stronie Bazy Systemowo-Sprzętowej.
UWAGA! W niektórych krajach szyfrowanie jest nielegalne. Jeśli znajdujesz się na terenie takiego kraju, to nie wolno Ci ściągać programów obsługujących szyfrowane połączenia, ani używać połączeń szyfrowanych.

Program

Żeby połączyć się z serwerem ssh, należy użyć programu do obsługi zdalnego terminala. Najpopularniejszym programem realizującym to zadanie jest PuTTy, którego wersję instalacyjną można ściągnąć z tej strony (link putty.exe prowadzi do najnowszej wersji instalacyjnej tego programu).
Czytelnik musi wiedzieć, że istnieją inne (według niektórych - lepsze) programy, którymi można łączyć się do serwerów ssh, ale na potrzeby wykładu będziemy korzystać z programu putty.

Połączenie

Po włączeniu PuTTy w polu Host Name należy wpisać nazwę serwera do którego chcemy się połączyć (np. mushelka.pjwstk.edu.pl) a następnie nacisnąć przycisk Open na dole okna.

Bezpieczeństwo

Przy połączeniu wyskoczy okno z komunikatem o próbie podłączenia się do nowego serwera, którego "odcisk palca" (ang. fingerprint) jest nieznany. Fingerprint jest bardzo trudno podrobić. Aby mieć pewność, że łączymy się do tego serwera, do którego rzeczywiście chcemy się połączyć (czyli: nasze połączenie nie zostało przekierowane przez hakera na inny serwer, który podsłuchuje co robimy), należy upewnić się, że (cały) fingerprint podany przez serwer jest prawidłowy. Należy przed połączeniem dowiedzieć się od administratora systemu, jaki jest fingerprint.

Uruchamianie interpretera

Logowanie się do systemu

Gdy użytkownik loguje się w systemie, system operacyjny uruchamia dla niego interpreter poleceń. Użytkownik widzi wtedy znak zachęty interpretera, np.

bash$ _
Może teraz wpisać nazwę programu, co spowoduje jego uruchomienie:
bash$ date <ENTER>
Fri Feb 28 13:34:34 MET 2003
bash$ _

Uruchomienie poleceniem

Interpreter poleceń jest zwykłym programem wykonywanym w ramach systemu operacyjnego. Ten, z którego korzystamy na tych zajęciach, nosi nazwę bash i dokładnie tak brzmi polecenie, które go uruchamiania. Można go więc też uruchomić z poziomu interpretera poleceń. Wtedy zaczniemy korzystać z owego nowouruchomionego interpretera poleceń:

bash$ bash <ENTER>
bash$ date <ENTER>
Fri Feb 28 13:34:34 MET 2003
bash$ exit <ENTER>
bash$ _


Skrypty

Poprzedni przykład jest oczywiście nieciekawy, ponieważ działanie, takie jak powyżej jest bezcelowe. Często wywołuje się jednak interpreter poleceń oddzielną instrukcją, po to, żeby wykonał skrypt, tzn. ciąg poleceń interpretera zapisany w pliku. Przypuśćmy, że w pliku skrypt1 umieszczono polecenie date. Wówczas ten skrypt można po prostu uruchomić (po nadaniu prawa do wykonywania tego pliku poleceniem chmod u+x skrypt1; szczegóły tego polecenia możesz znaleźć w systemowym podręczniku użytkownika. Aby go przejrzeć wydaj polecenie man chmod). Uruchomienie programu wygląda następująco:

bash$ ./skrypt1<ENTER>
Fri Feb 28 13:34:34 MET 2003
bash$ _
Wykonanie polecenia skrypt1 polega na (niejawnym) uruchomieniu interpretera poleceń i przekazaniu mu do wykonania poleceń z pliku skrypt1. Można też jawnie uruchomić interpreter i przekazać mu skrypt z instrukcjami do wykonania:
bash$ bash skrypt1<ENTER>
Fri Feb 28 13:34:34 MET 2003
bash$ _
Skrypty można też wywoływać z opcją -x. Przy takiej opcji interpreter wypisuje polecenia, które wykonuje, np.:
bash$ bash -x skrypt1
+ date
Mon Mar 17 14:10:46 CET 2003
bash$ _


Podstawowe polecenia

Aby móc pracować z interpreterem poleceń, należy poznać podstawowe komendy. Oto niektóre z nich:
polecenieopis
pwd - wyświetla ścieżkę do katalogu, w którym aktualnie się znajdujemy
cd - przechodzi do katalogu podanego jako pierwszy argument
ls - wyświetla zawartość bierzącego katalogu (lub katalogu podanego jako argument)
touch - tworzy plik o podanej nazwie (jeśli plik już istnieje, to ustawia ostatnią datę użycia na bierzącą)
cat - zawartość podanych plików zwraca na standardowe wyjście (domyślnie jest nim terminal)
mkdir - tworzy katalog o podanej nazwie
rm - "usuwa" pliki/katalogi podane jako argumenty (dlaczego "" - dowiemy się jeszcze w tym wykładzie)
cp - plik podany jako pierwszy argument kopiuje do pliku podanego jako drugi argument
mv - zmienia nazwę pliku podanego jako pierwszy argument na nazwę podaną jako drugi argument
man - wyświetla podręcznik użytkownika do polecenia podanego jako argument (np. man cat)
whoami - wyświetla nazwę użytkownika, pod którą jesteśmy zalogowani w systemie (można też: echo "$USER")
who - wyświetla aktualnie zalogowanych użytkowników (można też wyświetlić w innym formacie: users)

Edytory

nano

Nano's ANOther editor jest podstawowym edytorem preinstalowanym na praktycznie wszystkich systemach linuxowych. Zawiera on pięć podstawowych funkcji: Dostępne funkcje i skróty klawiaturowe, które te funkcje wywoują, znajdują się zawsze w ostatnich wierszach ekranu. Aby wyświetlić podręcznik użytkownika nano, należy użyć komendy
man nano

mcedit

Midnight Commander Editor jest bardzo prosty w użyciu i nie wymaga żadnego przygotowania. Nie jest on domyślnie instalowany na wszystkich systemach. W ostatnim wierszu edytora znajdują się opisy przycisków funkcyjnych (np. F3 włącza/wyłącza tryb zaznaczania, F5 kopiuje zaznaczenie, F8 usuwa zaznaczenie lub bierzącą linię). Ponadto klawisz F9 rozwija przejrzyste menu.
Uwaga: na niektórych typach terminali przyciski funkcyjne nie są rozpoznawane. W takim wypadku należy używać cyfr poprzedzonych klawiszem escape, np. zamiast klawisza F7 należy wcisnąć klawisz Esc a następnie cyfrę 7. Aby wyświetlić podręcznik użytkownika mcedit, należy włączyć program i wcisnąć klawisz F1.

Vim

Vim (VI iMprooved) jest bardzo zaawansowanym edytorem zoptymalizowanym pod kątem minimalizacji czasu edycji. Nauka obsługi tego programu trwa bardzo długo, ale warto nauczyć się jego obsługi, jeśli często korzysta się z pomocy edytorów terminalowych.

Przekierowanie wejścia-wyjścia

Każdy program ma trzy podstawowe strumienie wejścia-wyjścia. Są to:

Jeśli po prostu uruchomimy program, to w roli tych strumieni zawsze wystąpi terminal. Możemy jednak przekierować standardowe wyjście programu do pliku za pomocą znaku >, za którym podajemy nazwę pliku, np.
bash$ ls -alR / > drzewokat.txt
bash$ wc -l drzewokat.txt
557713
bash$ _
Program wc podaje kolejno liczbę linii, słów i znaków w plikach podanych mu jako argumenty (jeśli nie podamy żadnej nazwy pliku, to będzie liczył to co znajdzie na standardowym wejściu). Jeśli jako argument podamy mu flagę -l, to zwróci nam tylko ilość linii w pliku. Jeśli podamy mu flagę -c, to zwróci nam tylko ilość znaków.

Jeśli zamiast > użyjemy >>, to wynik programu zostanie dodany na końcu pliku drzewokat.txt, np.

bash$ ls -alR / > drzewokat.txt
bash$ wc -l drzewokat.txt
557713
bash$ ls -alR / >> drzewokat.txt
bash$ wc -l drzewokat.txt
1115426
bash$ ls -alR / >> drzewokat.txt
bash$ wc -l drzewokat.txt
1673139
bash$ _
Przy > plik, do którego przekierowujemy standardowe wyjście jest opróżniany przed rozpoczęciem wykonywania instrukcji.

Możemy też zlecić, żeby program czytał dane z pliku zamiast z terminala. Wystarczy w tym celu podstawić mu plik jako standardowe wejście za pomocą znaku <, za którym podajemy nazwę pliku, np.

bash$ cat > plik.txt
ala
ma
kota
^D
bash$ wc < plik.txt
      3       5      23
bash$ _ 
Najpierw za pomocą programu cat stworzyliśmy plik.txt. Ten program po prostu czyta standardowe wejście (albo pliki, których nazwy podano jako argumenty) i wypisuje to, co przeczytał na standardowe wejście. Po uruchomieniu czekał on na dane, które mu wpisaliśmy (ala ma kota) i zakończyliśmy Unixowym znakiem końca pliku (control-D). Potem ten plik przekazaliśmy jako standardowe wejście do programu wc, który policzył odpowiednie statystyki.

Przekierowanie standardowego wyjścia diagnostycznego wykonujemy poprzez frazę 2>, za którą podajemy nazwę pliku, np.

bash$ rm plik_ktorego_nie.txt 2> blad.txt
bash$ cat blad.txt 
rm: cannot lstat `plik_ktorego_nie.txt': No such file or directory
bash$ _ 
Polecenie rm służy do usuwania plików (usuwa pliki o nazwach podanych jako argumenty).

Bezpieczeństwo

Polecenie rm nie niszczy danych. Niszczony jest wyłącznie indeks wskazujący, gdzie jest przechowywany plik, a miejsce jest udostępniane do ponownego wykorzystania. Należy wiedzieć, że istnieją narzędzia, które pozwalają odzyskać tak "usunięte" dane. Do niszczenia poufnych danych powinno się używać np. narzędzia shred. W podręczniku użytkownika programu shred (man shred) czytelnik znajdzie więcej informacji na temat niszczenia danych.

Przetwarzanie potokowe

Często istnieje potrzeba potokowego przetwarzania danych przez kilka programów. Na przykład wiedząc, że polecenie sort sortuje leksykograficznie linie plików podanych jako argumenty (lub dane podane na standardowe wejście), a polecenie uniq usuwa powtarzające się sąsiednie linie, moglibyśmy napisać:
bash$ sort pl.txt > wynik1
bash$ uniq < wynik1 > wynik2
bash$ wc -l < wynik2

Istnieje prostsza (i szybsza, bo nie wymagająca wielokrotnego wykonania operacji zapisania/odczytania danych z dysku) metoda realizowania tego zadania.

Standardowe wyjście jednego programu można przekazać na standardowe wejście innego programu za pomocą znaku |, np.

bash$ sort pl.txt | uniq | wc -l
Ostatecznie otrzymujemy tu liczbę różnych linii w pliku pl.txt.

Taki potok może mieć dowolną długość i wykonywać całkiem niebanalne zadania


Wykonywanie w tle

Polecenie można wykonać w tle. Wówczas interpreter poleceń uruchamia odpowiedni program i pozwala użytkownikowi na wprowadzanie następnych poleceń. Aby uruchomić polecenie w tle, należy na jego końcu dodać znak &, np.

bash$ ls -alR / > drzewokat.txt &
[1] 10622
bash$ _
Polecenie ls wypisuje informacje o wskazanych plikach. W tej postaci szukamy plików od korzenia systemu (/), wszystkich plików (tzn. włącznie z plikami ukrytymi, opcja a), rekurencyjnie (opcja R) i z wypisaniem wyniku w długim formacie (opcja l). Wynik jest przesyłany do pliku drzewokat.txt (por. Przekierowanie wejścia-wyjścia). Oczywiście program wykonywany w tle nie powinien korzystać z terminala.

Jak widać system od razu umożliwia wpisanie następnego polecenia.


Podsumowanie

W wykładzie 2 przedstawiono interpretator poleceń. Jest to program, za którego pomocą uruchamia się inne programy. Szczególnie istotna jest możliwość przetwarzania potokowego i przekierowania standardowego wejścia-wyjścia. Bash ma wbudowany język skryptowy o sile pełnego języka programowania. Są w nim zmienne, wyrażenia arytmetyczne, logiczne, sterowanie, podprogramy i rekurencja. W kolejnych wykładach nauczymy się korzystać ze skryptów.


Słownik

argument skryptu
Słowa przekazane przy wywołaniu skryptu; są dostępne w treści skryptu; odczytujemy je za pomocą symboli $1, $2, ..., $9, $@ i $#.
instrukcja warunkowa
Instrukcja języka skryptowego umożliwiająca warunkowe wykonanie instrukcji.
instrukcja wyboru
Instrukcja języka skryptowego umożliwiająca uzależnienie wyboru instrukcji do wykonania od dopasowania pewnego wyrażenia do zbioru wzorców.
interpreter poleceń
Program, który oczekuje na polecenia użytkownika i po ich otrzymaniu je, wykonuje je. Wykonuje także polecenia języka skryptowego.
pętla
Konstrukcja programistyczna umożliwiająca wielokrotne wykonanie tej samej instrukcji.
podprogram
Funkcja albo procedura zadeklarowana i/lub wywoływana w skrypcie.
przekierowanie wejścia-wyjścia
Możliwość skojarzenia strumieni wejścia-wyjścia programu z plikami.
przetwarzanie potokowe
Wykonywanie programów w taki sposób, że standardowe wyjście jednego programu jest przekazywane na standardowe wejście innego.
skrypt
Ciąg poleceń interpretera zapisany w pliku. Zawiera wywołania programów, innych skryptów i instrukcje strukturalne.
standardowe wejście
Strumień, z którego większość programów czyta dane wejściowe.
standardowe wyjście
Strumień, do którego większość programów wysyła dane wyjściowe.
standardowe wyjście diagnostyczne
Strumień, do którego większość programów wysyła informacje o błędach, ostrzeżeniach i innych nieprawidłowościach.
środowisko programu
Składa się ze zmiennych i ich wartości. Jest przekazywane do wszystkich uruchamianych przez ten program programów. Program potomny ma dokładnie takie same środowisko jak program macierzysty.
tło
Miejsce wykonywania programów, które działając nie powstrzymują możliwości wprowadzania następnych poleceń.
zmienna
Nazwane miejsce przechowania wartości w interpreterze poleceń.
zmienna środowiskowa
Zmienna, która należy do środowiska programu.

Zadania

  1. (5p.) Odpowiedzieć na pytanie: co spowoduje wykonanie polecenia cat ../kot ?
  2. (5p.) Podać wynik polecenia cat /etc/shadow 2>&1 | wc -l

Strona przygotowana przez Marcina Kubicę i Krzysztofa Stencla.