6Kapitola

Bash 6: Roury, vstupy a výstupy

Neotřelým průvodcem ve světě shellu je Bohdan Milar .

Minule jsme si ukázali, jak obdělávat v Bashi pole a jak si přizpůsobit "rukojeť" tohoto nástroje (tedy prompt) vlastní potřebě. Nejen na poli je po zimě rušno. Také stavební dělníci mají plné ruce práce.

Bydlím na okraji města. Člověk by čekal za oknem romantickou přírodu, šumění větví a zpěv ptáků. Místo toho slyším bagry a vidím samé výkopy. Již druhým rokem se u nás buduje kanalizace. A tak mne napadlo, že se s vámi o tento zážitek podělím a budeme se dnes věnovat rourám. A protože do každé roury něco teče a na konci to teče ven, přidáme k tomu vstupy a výstupy.

Jak již jistě víte, v unixových systémech (jakým je i Linux) odvádí většinou práce spousta malých specializovaných prográmků. Např. při vypalování CD a DVD se používá mkisofs, cdrecord, cdrdao, cdrwtool, cdda2wav apod. Abychom si nemuseli pamatovat všechny parametry těchto textových příkazů, vznikají nástavby.

Při používání počeštěných termínů je dobré dávat pozor na jejich původní význam. Jednou na školení se mi povedlo oznámit posluchačům zhruba toto: "Tak to byl jeden příklad přesměrování. Protože už je ale 12:00, dáme si přestávku na oběd. Potom si ukážeme, jak to rourou hodit do wc." No a pak jsem mohl divit, proč na mne začátečníci tak nechápavě hledí a pokročilí se válejí smíchy.

Nástavbou pro vypalování CD je program, který téměř neví, co to CD je. Jeho úlohou je předložit uživateli hezké prostředí (např. okno s ikonkami, výpisem adresáře, dialog se záložkami pro konfiguraci apod.), pomocí kterého se na pozadí ovládá starý dobrý cdrecord a jeho kamarádi. Takovou nástavbou je třeba k3b v grafice nebo Bashburn v textovém režimu.

Prográmky spouštěné na pozadí se musejí nějakým způsobem domlouvat. To, co vyrobí jeden z nich, musí umět předat tomu dalšímu a tak pořád dál, dokud není úkol splněn. Řízení tohoto procesu je dalším úkolem nástavby nebo prostředí, v němž jsou programy spouštěny. Takovým prostředím je i Bash. Nástrojů pro zprostředkování komunikace mezi procesy má hned několik.

Výstupy

Většina textových GNU nástrojů během své práce nebo na jejím konci zobrazí výsledek této činnosti na terminálu, z něhož byl spuštěn. V tomto případě jde o tzv. standardní výstup. Často ani nevnímáme, že se na terminálu mísí dva různé výstupy - standardní a standardní chybový.

Znaky '<' a '>', které Bash používá k přesměrování vstupu a výstupu, nazývám v textu špičatými závorkami tak, jak jsem se to naučil ve škole. Není ale neobvyklé slyšet o nich jako o zobáčcích či šipkách doprava a doleva. Existují i zřejmě nespisovné výrazy většítko (od "větší než") a menšítko ("menší než"). Velmi originální je ovšem "šipka do Ruska" a "šipka do Německa".

Vezměme takový program pro výpis obsahu adresáře, tedy ls. Zadám-li ls /home, uvidím obsah adresáře /home, což je standardní výstup ls. Pokud ale udělám překlep a zadám ls /mohe, uvidím nejspíš hlášku "ls: /mohe: není souborem ani adresářem". To je standardní chybový výstup. Jeden příkaz může v rámci jedné operace vygenerovat oba typy výstupů.

Velkou výhodou unixového (a tedy i GNU) prostředí je, že oba tyto výstupy umí přesměrovat jinam než do terminálu. Bash k tomuto účelu využívá špičatou závorku doprava. Chceme-li např. vytvořit textový soubor s výpisem obsahu adresáře /home, využijeme k tomu příkaz ls, jehož výstup přesměrujeme do souboru seznam.txt.

Provedeme to příkazem ls /home > seznam.txt. Výsledek můžeme zkontrolovat pomocí cat seznam.txt. Analogicky můžeme zkusit ls /var > seznam.txt. Zkusíte-li si soubor prohlédnout teď, zjistíte, že jeho obsah byl přemazán výpisem adresáře /var. Co si ale počít, nechceme-li původní soubor přepsat, ale nová data připojit na jeho konec?

U přesměrování obou výstupů na stejné místo pomocí 2>&1 je třeba dbát na to, aby tento řetězec stál až za přesměrováním standardního výstupu. Jinak by byl totiž namířen tam, kam v tu chvíli míří standardní výstup, tj. na obrazovku.

Pro přesměrování do souboru s připojením (append) využívá Bash dvou špičatých závorek. Vyzkoušejte si následující posloupnost příkazů:

echo "*** DOMOVSKE" > seznam.txt
ls /home >> seznam.txt
echo "*** SYSTEMOVE" >> seznam.txt
ls /usr >> seznam.txt
cat seznam.txt

Tak jsme dosáhli, že místo toho, aby byl výsledek práce programu (nebo dokonce několika programů) zobrazen na obrazovce, bude uložen do souboru na disk.

Může ale nastat situace, kdy výsledek práce programu vůbec nepotřebujeme. Ba naopak by nás jeho výstup na obrazovce obtěžoval. Tehdy můžeme využít speciálního souboru, který nám unixové systémy nabízí, a to /dev/null. Ten v systému funguje jako černá díra. Co se tam hodí, to zmizí. Např. ls /home > /dev/null. Proč je dobré takový zdánlivý nesmysl někdy dělat, si ukážeme v některém z příštích pokračování.

Vedle vstupů a výstupů popsaných v článku existují ještě další mechanismy přesměrování, jako např. "Here Documents" a "Here Strings". Bližší informace o nich lze nalézt v manuálové stránce (man bash).

Vraťme se k překlepům, třeba ls /home /bni (mělo tam být samozřejmě /bin), a proveďme přesměrování standardního výstupu do souboru: ls /home /bni > seznam.txt. Do souboru se vypsal obsah /home a na obrazovce se objevilo chybové hlášení "ls: /bni: není souborem ani adresářem". Je to proto, že standardní chybový výstup jsme ponechali beze změny.

Standardní chybový výstup má interní označení 2 (1 je standardní) a toto číslo je nutné uvést (není-li uvedeno, je to bráno jako 1) před znak přesměrování. Nejlépe to ukáže příklad: ls /home /bni 2> chyby.txt. Nyní vidíme na obrazovce obsah /home a žádnou chybovou hlášku. Tu si naopak můžeme přečíst v souboru chyby.txt (třeba zadáním cat chyby.txt).

Můžeme být ovšem nároční a chtít přesměrovat oba výstupy současně. Uděláme to třeba následovně: ls /home /bni > seznam.txt 2> chyby.txt. Nyní je standardní výstup v seznam.txt a chybový v chyby.txt.

A na závěr případ, kdy chceme přesměrovat oba výstupy do téhož souboru. Abychom jméno (případně i s celou cestou) nemuseli psát dvakrát, stačí přesměrovat jeden výstup a druhému říci "tak, kam míří ten první": ls /home /bni > seznam.txt 2>&1. Už i toto je ale zastaralá a příliš dlouhá forma. Dnes stačí: ls /home /bni &> seznam.txt

 

Vstup

Podobně jako lze přesměrovat výstupy, je to možné udělat i se vstupem. Slouží k tomu špičatá závorka doleva. S touto funkcí se nesetkáváme tak často jako s přesměrováním výstupu, protože většina příkazů je připravena převzít vstupní soubor jako parametr.

Např. si vezměme takový cat. Když zadáme prostě cat bez parametrů, skočí nám kurzor na nový řádek a čeká na (standardní) vstup - z klávesnice. Zadáme-li určitý text zakončený klávesou Enter, provede s ním cat to, k čemu je předurčen - pošle jej na standardní výstup. Tento režim ukončíme kombinací kláves [Ctrl+d].

Většinou ale cat používáme k výpisu obsahu souboru, tedy nikoli standardního vstupu. Po zadání cat list.txt uvidíme na standardním výstupu obsah souboru list.txt. Stejný efekt by ovšem mělo cat < list.txt

Ještě stále najdeme pár programů, které pro práci se souborem vyžadují přesměrování vstupu. Patří mezi ně i cpio. Pokud chceme např. rozbalit archiv se jménem archiv.cpio, musíme zadat cpio -i -d < archiv.cpio (parametr -i značí rozbalit, -d vytvořit potřebné adresáře).

Potrubní pošta aneb Roury

Roura je mocný nástroj. Jde o spojení obou typů přesměrování. Přesněji řečeno přesměrovává standardní výstup jednoho programu na standardní vstup druhého programu. Používá se k tomu znak '|' (známý též jako svislítko).

Např. cat má přepínač -n, s jehož pomocí čísluje řádky svého výstupu. Řekněme, že bychom chtěli ve výpisu adresáře jednotlivé soubory očíslovat. Není proto nic snadnějšího než zadat ls | cat -n. Nebo něco zábavnějšího: ls | rev

Problémem bývají pro mnoho uživatelů dlouhé výpisy z některých programů. Již jsme si ukázali, jak je přesměrovat do souboru, který pak můžete otevřít a prozkoumávat třeba ve svém oblíbeném editoru. Proč se ale zdržovat a zaplácávat disk dočasnými soubory, když tuto práci zvládneme v příkazovém řádku? Na prohlížení dlouhých souborů je třeba vhodný less: ls -l /etc | less (program opustíte klávesou q).

Stránkovač less je velice mocný a poskytuje zkratkové klávesy z editoru vi. Například hledání regulárních výrazů pomocí lomítka je velmi praktické.

Programem často využívaným v této potrubní poště je grep - nástroj na vyhledávání řetězců. Ten zajistí, že budou vypsány jen ty řádky, které obsahují hledaný řetězec. Hledáme např. všechny spuštěné instance Bashe. K výpisu běžících programů slouží ps: ps aux | grep bash

Příznivci DOSu by mohli namítnout, že takovou rouru měl jejich oblíbený systém již dávno. Ano, byla tam, ale velmi omezená. Co je totiž na unixové rouře pozoruhodné, je možnost jejího spojování do dlouhého potrubí.

Řekněme, že bychom chtěli výše vypsaný seznam spuštěných Bashů (pokud jste měli jen jeden, tak si jich bokem z testovacích důvodů pár spusťte) abecedně setřídit (v prvním poli je uživatel, který daný proces spustil): ps aux | grep bash | sort

To stále není vše. Můžeme pokračovat ve stavbě dále. Dejme tomu, že z takto dosaženého výpisu budu chtít zobrazit jen tu část řádku od výpisu terminálu, na kterém Bash běží (tj. od 37. znaku včetně). Zadám jednoduše: ps aux | grep bash | sort | cut -c 37-

A tak bych mohl pokračovat dál a dál. Očíslovat řádky (cat -n), spočítat znaky (wc), obrátit pořadí znaků v řádku (rev), ... Délka potrubí není omezena a fantazii se meze nekladou.

Vraťme se ale ještě k tématu prostého přesměrování výstupu. Zkusme ls /home /sibn | cat -n. Řádek s chybou není číslován. Neprošel totiž rourou. Byl vypsán přímo programem ls. Co kdybychom ovšem chtěli do roury poslat i chybový výstup? Půjde to takhle: ls /home /sibn 2>&1 | cat -n.

Ještě se zmiňme o možnosti přesměrovat výstup do souboru a zároveň jej ponechat na obrazovce. Slouží k tomu příkaz tee, do nějž výstup předchozího procesu pošleme rourou. Příklad: ls /boot | tee seznam.txt a potom cat seznam.txt. Uvidíme dvakrát totéž.

Pojmenované roury

Roury, o kterých jsme mluvili v minulých odstavcích, jsou jako nestabilní červí díry. Jeden průlet a díra zmizí. Co ale kdybychom chtěli nějakou rouru využívat opakovaně? Linux nám k tomu nabízí mechanismus zvaný pojmenovaná roura (named pipe).

Pojmenovaná roura je speciálním typem souboru existujícím v souborovém systému. K jejímu vytvoření slouží program mkfifo. Syntaxe je jednoduchá. Stačí zadat jen její jméno, např. mkfifo roura. Že nejde o běžný soubor, si můžeme ověřit příkazem ls -l roura. Na začátku bloku s přístupovými právy vidíme "p" - pipe.

Nyní můžeme do roury něco poslat, třeba přesný čas: date > roura. Nelekejte se, pokud se neobjevil prompt. To je v pořádku. Proces čeká na vyprázdnění roury. Spusťme tedy jinou konzoli nebo terminál, přejděme do adresáře, kde leží naše pojmenovaná roura a zadejme třeba cat roura. Ve druhém Bashi budou vypsány příslušné údaje a v prvním se objeví prompt.

Funguje to i obráceně. Můžeme nechat nějaký proces číst z prázdné roury (cat roura). Ten bude čekat až do doby, kdy se roura zaplní. To provedeme třeba informacemi o našem systému (uname -a > roura) na jiném terminálu. Až nyní cat svou práci dokončí.

Tohoto chování lze využít v mnoha situacích. Dostaneme se k nim v budoucnu, až budeme tvořit shellové skripty. Na jednu drobnost bychom neměli zapomínat - uklidit po sobě. Pojmenovanou rouru smažeme podobně jako běžný soubor: rm roura.

Závěr

Doufám, že se v tom potrubním systému neztratíte. Je to vskutku velmi silný nástroj, i když k jeho plnému využití je dobré znát pár GNU nástrojů, které mezi dvěma rourami fungují jako dobré filtry.

No a čemu že se budeme věnovat příště? Dělám si zálusk na přezdívky (aliasy) a věci s nimi spojené. Dozvíte se proto také, jak se nastavuje Bash pomocí konfiguračních souborů.