Vítám všechny zájemce o práci s textovým interpretrem Bash u druhého dílu našeho seriálu. Minule jsme si předvedli, kterak se do textového prostředí vůbec dostat. Zabývali jsme se také způsobem zadávání příkazů - jejich syntaxí.
Náplní dnešního dílu budou některé interní příkazy a klávesové zkratky související s řízením procesů - tedy programů spuštěných z Bashe. Ukážeme si také výhody kooperace textového a grafického prostředí.
Úlohy v pozadí a na popředí
V dobách, kdy byly procesory pomalé, trvalo vykonání některých příkazů dlouho. I paměti bývalo tehdy v počítačích mnohem méně, a proto nebylo žádoucí spouštět hodně interpretrů paralelně. Aby i tehdy bylo možné co nejlépe využít víceúlohového prostředí (multitaskingu), zavedly interpretry možnost přepnout program spuštěný v textovém prostředí na pozadí.
Spustit nebo přepnout program na pozadí znamená, že v průběhu jeho běhu máme k dispozici prompt a můžeme zadávat další příkazy. Ptáte-li se, proč tento historický nástroj zmiňuji v době, kdy máme dost paměti k pouštění velkého množství Bashů vedle sebe, vězte, že i dnes má toto řízení procesů své uplatnění.
Ačkoli je to paradox, tak učit se řídit procesy v Bashi má dnes největší význam díky prostředí X Window System. Jsou uživatelé, kteří příkazovou řádkou opovrhují a pracují pouze graficky. Jsou tací, kteří opovrhují grafikou. Také jsou uživatelé, kteří by grafiku využívat chtěli, ale něco jim v to brání - nedisponují dost silným hardwarem k provozu X, mají ke stroji přístup jen přes ssh, jsou nevidomí (pro nevidomé je zatím uspokojivá podpora jen v textovém prostředí) apod.
Mnoho uživatelů ovšem dospělo k názoru, že obě prostředí mají své výhody a nevýhody. Díky systémové integritě Linuxu je naštěstí lze velmi komfortně používat společně a kombinovat tak výhody obou. Docílíme toho spuštěním virtuálního terminálu v prostředí X (Konsole, gnome-terminal, xterm, ...), čímž získáme Bash v okně. To nám umožní nejen rychle přecházet mezi oběma prostředími, ale používat i různé systémové nástroje pro jejich spolupráci.
Jednou z forem spolupráce je kopírování textu. Např. výstup nějakého textového příkazu můžeme v terminálovém okně označit myší (táhnutím při držení levého tlačítka), čímž jej automaticky uložíme do schránky. Obsah schránky pak vysypeme (třeba prostředním tlačítkem myši) do jakéhokoli okna, kupříkladu textového editoru kedit nebo textového procesoru OpenOffice.org Writer. Kopírování samozřejmě funguje i obráceně.
Bezproblémová spolupráce grafických a textových aplikací je možná díky tomu, že v nich jádro systému (kernel) nedělá rozdíly. Problémem tak není ani nastartovat grafickou aplikaci z terminálového okna. Stačí napsat jméno spustitelného souboru jako příkaz, odenterovat a program se spustí. Do terminálu pak někdy dokonce vrací informace o průběhu své činnosti. A tím se dostáváme k důvodu, proč nás zajímá řízení grafických procesů z Bashe.
Spustíme-li prostřednictvím Bashe nějakou aplikaci v grafickém prostředí, neukáže se nám prompt dříve, než tato aplikace skončí. Pouštět přitom aplikace z terminálu bývá výhodné. Známe-li jméno programu, je jeho napsání rychlejší než hledání v často rozsáhlé spouštěcí nabídce (viz ikona na panelu, nejčastěji vlevo dole). Některé aplikace dokonce ani položku v hlavní nabídce mít nemusejí. Dalším důvodem jejich spouštění z příkazové řádky je možnost zadat různé parametry.
Jak to tedy udělat, abych měl k dispozici po spuštění Xové aplikace opět prompt, mohl dále pracovat nebo spustit aplikaci další? O kombinaci [Ctrl+c] jsem mluvil minule. Ta ovšem vede k ukončení aplikace, a to my zde nechceme. Řekněme, že jsem z terminálu spustil gkrellm - panel pro monitorování systému, který mi teď blokuje prompt. Aplikace běží a kurzor v Bashi stojí (nebo bliká) bez promptu na začátku nového řádku.
Takto běžící program můžeme z terminálu zastavit kombinací kláves [Ctrl+z]. Objeví se hláška Stopped. Od tohoto okamžiku sice máme zase prompt, ale program je zamrzlý. Aby mohl ve své činnosti pokračovat, musíme mu povolit činnost na pozadí příkazem bg. Po odentrování se ihned rozběhne.
Existuje ale i způsob, jak spustit grafickou aplikaci na pozadí přímo. Dělá se to přidáním znaku ampersand (&) za příkaz spouštějící aplikaci. Tak např. XMMS spouštíme z příkazové řádky zadáním xmms &. Po odentrování dostaneme zpátky prompt a (někdy s drobnou prodlevou) také okno spouštěné aplikace.
Řízení více souběžných procesů
Z výše zmíněného vyplývá, že programů na pozadí můžeme z jednoho shellu spustit více souběžně. Jak se v nich potom ale vyznat, když jim chceme posílat různé signály? Jednoduše, neboť Bash si tyto úlohy (anglicky jobs) čísluje. Seznam běžících (Running) nebo stojících (Stopped) úloh získáme příkazem jobs.
V seznamu vidíme na každém řádku jednu úlohu. V hranaté závorce je uvedeno číslo úlohy, následuje status (Running/Stopped) a zakončuje jméno, resp. příkaz, kterým jsme úlohu spustili. Velmi důležité je zde číslo úlohy, pomocí něhož můžeme jednotlivé z nich oslovovat.
Chceme-li např. vrátit z pozadí do popředí úlohu číslo 2, zadáme fg %2. Bash vypíše jméno příslušné úlohy a začne ji provádět na popředí, tj. nevrátí nám prompt. Ten bychom získali známým postupem [Ctrl+z] a bg %2.
Každý Bash si v sobě spuštěné úlohy čísluje vzestupně od čísla 1. V každém Bashi tak můžeme komandovat pouze ty úlohy, které byly spuštěny právě v něm. Při spuštění každé úlohy se nám ale za jejím číslem (v hranatých závorkách) ukáže vždy ještě jedno, zpravidla čtyř- až pětimístné číslo. To značí číslo procesu v rámci celého systému (tzv. PID).
Nyní se podíváme ještě na pár parametrů příkazu jobs. Zadáme-li Bashi požadavek ve tvaru jobs -l, zobrazí se nám mezi číslem úlohy a jeho stavem ještě PID. jobs -r vypíše pouze běžící úlohy, jobs -s pak pouze ty zastavené. Přepínače lze samozřejmě kombinovat, takže po jobs -lr dostaneme seznam běžících úloh s PID.
PID je unikátním celým číslem (každé číslo náleží právě jednomu procesu v běžícím systému), které jádro přiděluje vzestupně každému spuštěnému procesu. Číslo 1 má vždy proces init, který je v systému spuštěn jako první.
Pro zjišťování PID kteréhokoli z běžících procesů (tedy nejen úloh spuštěných v rámci příslušné instance interpretru Bash) slouží program ps. Když jej spustíme bez přepínačů (kterých má vskutku požehnaně), uvidíme jen aktuální Bash, seznam spuštěných úloh a vlastní běžící ps.
U každého vypsaného procesu můžeme zjistit jeho PID, na kterém běží terminálu (tty2 je druhá virtuální konzole - [Ctrl+Alt+F2], pts/1 je první virtuální terminál - např. okno s Bashem v rámci X), využitý strojový čas a příkaz, kterým byl proces spuštěn.
Z dalších přepínačů vyberme:
- ps x - vypíše všechny procesy daného uživatele bez ohledu na terminál (Bash) a s celou syntaxí příkazu;
- ps a - vypíše procesy všech uživatelů na daném terminálu;
- ps u - vypíše procesy s uvedením uživatele, zátěže CPU a RAM;
- ps j - vypíše procesy s uvedením mj. PID rodičovského procesu (tzv. PPID).
Jednotlivé přepínače ps lze samozřejmě kombinovat. ps aux tak bude mít za následek seznam všech procesů na všech terminálech s celou syntaxí příkazu, kterým byly spuštěny.
Kill aneb Bash zabiják
Již jsme si řekli, jak se na spuštěné úlohy podívat a jak je přepínat do popředí a do pozadí. Teď si ukážeme, jak ukončit (též sestřelit nebo zabít) nějakou úlohu na pozadí. Lze to samozřejmě udělat tak, že ji nejprve přepneme do popředí a potom ukončíme klávesovou kombinací [Ctrl+c]. Existuje ale i jiný způsob.
Seznamme se s legendárním příkazem kill (anglicky zabít). Dle názvu bychom mohli mylně usuzovat, že je práce tohoto nájemného vraha jednotvárná. On je to ale ve skutečnosti nevinný pošťák, který doručuje jednotlivým procesům balíčky s příkazy. Naneštěstí pro jeho pověst v těch balíčcích tu a tam bývá bomba.
Seznam typů těchto balíčků, nebo chcete-li nařízení (v unixovém jazyce hovoříme o signálech) najdeme mj. v manuálové stránce (man 7 signal). Nelekejte se široké nabídky, budeme z nich potřebovat jen pár. Vlastně nás bude zajímat jen číslo 9, což je již zmiňovaná dopisní bomba.
Abychom určili adresáta, použijeme číslo úlohy (třeba kill %3) nebo číslo procesu (PID - např. kill 7190). Pokud neuvedeme, jaký signál procesu posíláme, bude doručen SIGTERM, tedy číslo 15. Stiskneme-li potom na prázdném promptu [Enter], uvidíme hlášku ve stylu [3]- Ukončen (SIGTERM) kedit.
Pro doručení jiného signálu uvedeme jeho číslo (nebo jméno) s pomlčkou. Pokud třeba program nereaguje na SIGTERM (třeba protože je zaseknutý), můžeme jej násilně ukončit (zabít, sestřelit) signálem 9 (SIGKILL) takto: kill -9 %2. Po odentrování prázdného řádku uvidíme kupř. [2]+ Zabit (SIGKILL) ksnake.
Pro přípravu úkladné vraždy bývá dobré vytipovat si oběť. K tomu nám dopomůže nástroj top. Je to interaktivní textový program, tzn. že po spuštění reaguje na určité klávesy. Jeho úlohou je zobrazovat seznam běžících procesů seřazených dle určité charakteristiky.
Zkusme si prostě spustit top. Uvidíme záhlaví s aktuálním časem a údaji o systému. Pod ním je tabulka procesů uvozená inverzním záhlavím. Tabulka se každých pět sekund aktualizuje. Chod programu můžeme ovlivnit mj. těmito klávesami:
- [Shift+n] - třídění procesů podle PID;
- [Shift+a] - třídění procesů podle PID od konce;
- [Shift+p] - třídění procesů podle zatížení CPU (odhalení zaseknutých procesů);
- [Shift+m] - třídění procesů podle objemu zabrané paměti (odhalení viníků swapování);
- [Shift+t] - třídění procesů podle spotřebovaného strojového času (odhalení procesů nejvíce zatěžujících systém);
- [Shift+a] - třídění procesů podle PID od konce;
- [m] - zapnutí nebo vypnutí informací o paměti;
- [t] - zapnutí nebo vypnutí souhrnných informací o systému;
- [h] - nápověda;
- [q] - ukončení programu.
Po zjištění viníka našich problémů nemusíme top opouštět. Po stisknutí [k] budeme vyzváni k zadání PID, kterému chceme poslat balíček. Po odentrování správného PID nám bude nabídnuto zadání signálu. Nezadáme-li žádný, bude odeslán SIGTERM (15).
Závěr
Přeji příjemnou zábavu s krocením poslušných i neposlušných procesů. Problematiku jsme probrali sice trochu letmo, ale myslím si, že ve značné šíři. Komu by chyběla hloubka, může bádat v manuálových stránkách příslušných programů nebo přímo v man bash.
Příště bych se chtěl zabývat různými způsoby, jak programy v Bashi spouštět, zřejmě se ale nevyhneme také úvodu do problematiky proměnných prostředí.