Hlavní navigace

Hrátky z řádky: kombinace procesů

11. 2. 2008
Doba čtení: 4 minuty

Sdílet

Jednoduché příklady přesměrování do souboru a roury spojující dva procesy už jste v našem seriálu několikrát viděli. Dnes možnosti přesměrování a kombinací procesů projdeme trochu komplexněji. Zkušení unixáři všechno tohle vědí, teď cílíme na začátečníky. I když občasné opakování nemusí škodit nikomu.

Dopředu jedno varování: používáme syntax bashe (typicky /bin/bash), jiné shelly, např. csh, mohou požadovat zápis jiný.

Vstup a výstup procesu

Terminologie úvodem: „program“ je spustitelný soubor, „proces“ je pak jedna konkrétní běžící instance nějakého programu. Často tenhle jemný rozdíl nehraje roli, ale když např. jeden program spustíte dvakrát, je jasné, že musíte začít mluvit o procesech.

Odkud odevšad získává unixový proces nějaká vstupní data (pomineme-li např. síťové připojení)?

  • vlastní kód programu, co je „zadrátováno“
  • standardní vstup (stdin)
  • příkazová řádka, tj. název programu a parametry, které dostal
  • proměnné prostředí (např. $USER obsahující vaše uživatelské jméno)
  • systém souborů (filesystem), kolik přístupová práva dovolí

Jednotlivé zdroje vstupů se liší svým charakterem:

  • Příkazová řádka i proměnné prostředí jsou vhodné jen na relativně malá data, například nastavení parametrů, krátký seznam souborů ke zpracování a podobně.
  • Proměnné prostředí se (na rozdíl od všeho ostatního) dědí i pro procesy, které původní proces sám spustí.
  • Standardní vstup může být neomezený do délky, nelze však v něm číst na přeskáčku nebo se vracet. Toho lze dosáhnout jen tak, že si část vstupu načteme a zapamatujeme. Hloupé programy načítají celý vstup, i když to třeba vůbec najednou nepotřebují, a nedokážou tak zpracovat větší vstup, než se vejde do paměti. Navíc je standardní vstup jen jeden.
  • Systém souborů dovoluje prakticky cokoli, ale program přirozeně potřebuje napovědět, se kterými soubory pracovat, aby nemusel prohledávat všechny disky.

A co všechno může proces vracet?

  • standardní výstup (stdout),
  • chybový výstup (stderr),
  • návratovou hodnotu (exit code), tj. jedno celé číslo,
  • a samozřejmě může nějak modifikovat systém souborů, například něco někam uložit.

Povšimněte si, že program nemůže „vracet“ proměnné prostředí, ty lze měnit jen pro potomky, nikoli pro předky. Řeč je o „rodokmenu“ procesů podle toho, kdo koho spustil.

K čemu výše uvedený přehled? Každý program je jiný, předpokládá vstup jinde a vrací výstup jinam (nebo nás může zajímat něco méně obvyklého). Je tedy potřeba pečlivě číst manuálové stránky programů, abychom program spustili správně.

Základní přesměrování a roury

Jako příklad uvažme tr, program pro zaměňování písmenek. tr však na rozdíl od například cat zpracovává zásadně stdin, nikoli soubory uvedené na příkazové řádce. Vstup ze souboru je tedy nutné na stdin nějak přivést, a to přesně shell umožňuje. Zde je příklad použití tr, který každé slovo textu uvede na samostatný řádek (záměnou mezer za znak konce řádku). Shell v zadaném příkazu najde pokyn pro přisměrování vstupu (<), otevře udaný soubor.txt, spustí tr a přivede mu obsah souboru na standardní vstup:

$ tr ' ' '\n' < soubor.txt

Roura ( |) v příkazové řádce značí, že dva procesy na sebe navazují: standardní výstup jednoho je rovnou předán na standardní vstup druhého. Pro zpracování komprimovaného vstupu v našem příkladu napřed necháme soubor.txt.gz rozbalit (program gunzip) a vypsat ( -c; bez tohoto parametru gunzip rozbalí soubor „na místě“ a nic nevypíše), roura pak text souboru přivede na vstup tr:

$ gunzip -c soubor.txt.gz | tr ' ' '\n'

Výstup z  tr často chceme nikoli vypsat, ale raději uložit:

$ ... | tr ' ' '\n' > vystup.txt

nebo opět rovnou komprimovat:

$ ... | tr ' ' '\n' | gzip > vystup.txt.gz

Přesměrování chybového výstupu

Nyní už možná chápete, proč Unix odlišuje standardní a chybový výstup. Cenná data obyčejně tečou z programu do programu standardním výstupem a není žádoucí do nich přimíchat občasné chybové hlášky nebo upozornění. Právě k tomu slouží chybový výstup. Neurčíte-li jinak, chybový výstup se bude vypisovat na konzoli. V bashi můžete ale pohodlně chybový výstup přesměrovat do samostatného souboru nebo do „černé díry“ /dev/null (speciální zařízení, které vše rovnou zahazuje). Zde je příklad, který prohledá celý disk. Protože však k řadě adresářů nemáte přístup, chybový výstup zahltí vaši konzoli stížnostmi a šťastně nalezený soubor (uvedený na standardním výstupu) můžete snadno přehlédnout. Chybový výstup tedy přesměrujeme do černé díry:

$ find / -name hledany_soubor.txt 2> /dev/null

Chybový výstup můžete rourou rovnou předat i jinému programu (například grep pro vyhledání právě té chybové hlášky, která vás zajímá), musíte ale napřed přesměrovat chybový výstup na standardní (roura navazuje zásadně na standardní výstup). Takto spojíte standardní a chybový výstup dohromady:

$ find / -name hledany_soubor.txt 2>&1 | less

A takto standardní výstup pošlete do souboru a chybový povedete rourou:

$ find / -name hledany_soubor.txt 2>&1 > nalezene_soubory.txt | less

Upozorňuji, že pořadí, v jakém přesměrování uvedete, je podstatné. Intuici odpovídá, když budete číst pokyny odzadu: stdin do souboru, stderr na stdin. opačné pořadí ( > soubor 2>&1) pošle vše do souboru a nic do roury.

Přesměrování do chybového výstupu

Pro výpis dlouhé chybové hlášky (například z nějakého delšího skriptu, až je společně začneme programovat) se může hodit opak: přesměrovat standardní výstup na chybový:

Cloud 24 - tip 1

$ cat dlouha_chybova_hlaska.txt >&2

Pozorní čtenáři si všimli, že stdout má „číslo“ 1 a stderr „číslo“ 2. Je tomu skutečně tak, vstupy a výstupy programu jsou číslovány, takzvané file deskriptory, ale to už opravdu přesahuje základy shellu.

Víc už se nám do tohoto dílu nevejde, příště nás čeká zase kousek teorie, tentokrát o mezerách v příkazové řádce a kapinku o proměnných prostředí.

Byl pro vás článek přínosný?