Wiele zadań na jednej konsoli

Linuks (ogólnie un*xy) jest z założenia systemem wieloużytkownikowym, czyli na raz może być na nim zalogowanych wielu użytkowników (zdaje się do 32000). Wieloużytkownikowość pociąga za sobą wielozadaniowość (każdy user chce coś robić). Jak jednak użyć tej wielce użytecznej cechy Linuksa? To teoretycznie zależy od używanej powłoki, w praktyce jednak większość shelli stosuje tę samą konwencję. Opiszę jednak szczegóły odwołując się do basha (chyba najpopularniejsza, a na pewno ja sam jej używam).
Pierwszą sprawą, jaką powinieneś poznać, to sposoby kończenia programu. Nie mam tu na myśli kończenia przez wybór odpowiedniej opcji z menu programu, bo nie zawsze program musi mieć menu (choćby taki napisany przez ciebie). Przede wszystkim jest kombinacja klawiszy ^C (tak jest oznaczane Ctrl+C w zapisie, jakim będę się tu posługiwał). Ta kombinacja powoduje wyjście z programu.
Jeśli chcesz zatrzymać program na chwilę, możesz wcisnąć ^Z. Zobaczysz linię w stylu

[1]+ Stopped       nazwa-programu

To jest linijka statusu zadań, możesz ją powtórnie przywołać poleceniem jobs (to jest wbudowana komenda basha). Liczba w nawiasie kwadratowym to numer zadania (bo może być ich kilka), który jest użyteczny dla niektórych komend wbudowanych. Jest unikalny na danej konsoli, ale na innych konsolach już nie możesz się odwoływać przez ten numer. Dalej jest status pracy (zatrzymana, pracuje, zakończona i parę innych) i komenda, jaką praca została uruchomiona. No to teraz przydałaby się komenda przywracająca zadanie na pierwszy plan (tzw foreground): fg. Podane bez argumentów fg przywraca pracę, która ostatnio była aktywna (to ta z plusem koło numeru pracy, przedostatnia zaś ma minus). Jeśli chcesz przywrócić pracę o konkretnym numerze, to za argument fg podaj właśnie ten numer: fg 14 przywróci pracę z numerem 14 (fg - przywróci przedostatnią). Możesz też odesłać pracę w tło, jeśli nie chcesz, żeby zajmowała ci terminal, na przykład kopiowanie dużego pliku. Możesz w tym momencie podawać inne polecenia, równolegle z tamtym zadaniem. Do takiego tricku służy bg, które działa identycznie jak fg (z dokładnością do tego, że odsyła pracę w tło, tzw. background). A jeśli chcesz wysłać pracę w tło od razu, nie usypiając jej kombinacją ^Z, to na końcu polecenia dodaj znaczek & (przykład: cp duzy-plik nowa-lokacja &).
Procesy mogą zmieniać swój status w trakcie wykonywania, na przykład proces wykonywany w tle może zacząć czekać na wejście z klawiatury (wtedy jest zatrzymywany, aż do przejścia na foreground) albo jakiś proces może się skończyć. Takie zmiany są sygnalizowane komunikatem wypisywanym tuż przed znakiem zachęty (znaczy wtedy, gdy ma być wypisany na nowo, czyli po wydaniu komendy).
Jeszcze zostało polecenie kill. Nazwa wskazuje na to, że tak można zabić jakiś program. Owszem, choć polecenie raczej wysyła do programu sygnał o określonym numerze. Domyślnie jest to sygnał 15, oznaczany nazwą SIGTERM. Jest to dobry sygnał, w większości sytuacji powoduje miękkie zakończenie programu. Jednak program może przechwytywać pewne sygnały (dokładnie to program może przechwycić wszystkie sygnały poza dwoma), albo może będziesz chciał wysłać inny sygnał (na przykład przy pisaniu programu).
Podstawowe zastosowanie polecenia: kill 1234 lub kill %2. Pierwsze zabije proces o identyfikatorze 1234 (identyfikator, czyli PID, to numer przydzielony procesowi przez system, jest on unikalny w skali sesji), w drugim przypadku kill zabije zadanie drugie z listy procesów uśpionych i działających w tle. Do wysyłania sygnałów innych niż SIGTERM służą opcje: kill -s SIGTERM <proces> wysyła sygnał SIGTERM do procesu <proces> (oczywiście tutaj wpisujesz numer zadania albo PID); kill -n 15 <proces> lub kill -15 <proces> wysyła sygnał numer 15 do procesu <proces>. Jeśli chcesz listę sygnałów, wpisz kill -l.
Wiesz teraz, jak wysyłać sygnały, ale nie wiesz, które wysyłać. Ogólnie, sygnał 15 SIGTERM standardowo kończy zadanie, sygnał 2 SIGINT to sygnał posłany przy wciśnięciu ^C, 20 SIGTSTP jest wysyłany po wciśnięciu ^Z, natomiast sygnały 9 SIGKILL i 19 SIGSTOP są nieprzechwytywalne z założenia, dzięki czemu zawsze możesz zastopować/zabić proces (to jest słynne polecenie: kill -9, zabija bezwarunkowo).
Uwaga dotycząca różnych systemów operacyjnych: sygnały SIGSTOP i SIGTSTP mogą mieć inne numery, ale na pewno te same nazwy.
Jeszcze przydałoby się wiedzieć, do jakiego procesu wysłać SIGKILL :-) Jednym z najpopularniejszych poleceń do zarządzania procesami (w tym ich kończenia) jest top (table of processes). Nie potrzebuje żadnych parametrów. Po uruchomieniu dostajesz spis procesów, który prawdopodobnie nie mieści się na ekranie. Przyznaję się bez bicia, że nie potrafię przewijać tej listy. Ale możesz sobie ograniczyć wyświetlane procesy do aktywnych (literka i, komenda typu włącz/wyłącz) albo do konkretnego użytkownika (literka u, po której wpisujesz nazwę usera). Wychodzisz wciskając q. Uwaga: top zdaje się nie występować na Solarisie.
Drugim popularnym poleceniem jest ps. To z kolei jest chyba na każdym un*xie. ps po prostu wypisuje procesy. Domyślnie listuje zadania z aktualnej konsoli. Żeby wylistować wszystkie zadania użytkownika wpisz ps -u <login>. Do wylistowania wszystkie zadania (nie tylko twoje) służy ps -A. Ja sam często stosuję ps -Af, dostaję wtedy zamiast samej nazwy procesu pełne polecenie, jakim został proces uruchomiony.

Możesz uruchamiać kilka poleceń na raz, oddzielając je średnikiem. W zasadzie odpalą się jedno po drugim. Jeśli chcesz je uruchomić jednocześnie, to oddizel je znaczkiem &. Tak, tym samym, który służy do puszczania procesu w tle (do tego przecież się sprowadza uruchomienie współbieżne dwóch lub więcej programów). Są jeszcze bardziej zaawansowane sposoby uruchamiania sekwencji programów, ale te opiszę w zasadzie pod koniec koorsu (bo tam dopiero się przydadzą).

Jeszcze słówko nie do końca o wielozadaniowości, ale czasem przydatne. Jeśli uruchomisz jakiś program, który nic nie chce wypisywać na ekranie (np. ed lub cat), to prawdopodobnie odpaliłeś program czekający na dane ze standardowego wejścia (później wyjaśnię, o co chodzi). Często wystarczy wcisnąć ^D, żeby program się zakończył. Otóż ^D to znaczek używany przy przesyłaniu danych na oznaczenie końca strumienia danych. Gdy program czekający na wejście otrzyma taki znaczek, to kończy pobieranie danych. Wtedy nie ma żadnych danych do operowania na nich, więc się kończy. Spróbuj tego również z shellem :-).


Dalsza część kursu
Poprzednia część kursu
Jadłospis