Přesměrování vstupu a výstupu, roury, filtry

Existují dva podstatné prostředky výstupu, stdout (standardní výstup) a stderr (chybový výstup). Smysl tohoto dělení je v tom, že lze kterýkoliv z nich (nebo oba) přesměrovat jinam. Pro vstup je určen stdin (standardní vstup). Vstup a výstup se běžně tiskne na obrazovku, ale lze jej přesměrovat jinam (třeba do souboru) pomocí většítka a menšítka. Jak to všechno funguje v praxi si nyní ukážeme.

Řekněme, že bychom chtěli výpis obsahu adresáře uložit do souboru. V tom případě bychom rádi přesměrovali standardní výstup do souboru, což provedeme takto:

  [michal@griffon ~]$ ls -l > vypis.txt

Pokud použijeme dvě většítka za sebou, soubor vypis.txt se nepřepíše, výpis se připojí na konec souboru:

  [michal@griffon ~]$ ls -l >> vypis.txt

Stejně jako výstup lze přesměrovat i vstup, a příslušnému programu je tak možné poslat data ke zpracování z nějakého souboru (místo z klávesnice). Zkusme třeba tohle:

  [michal@griffon ~]$ sort < vypis.txt

Program sort umí setřídit řádky podle určitých kritérií. Tento příkaz způsobil, že program sort zpracoval řádky v souboru vypis.txt a setřídil je výchozím způsobem.

Vstup i výstup lze přesměrovat najednou:

  [michal@griffon ~]$ sort < vypis.txt > setrideno.txt

Tímto příkazem jsme setřídili řádky souboru vypis.txt a výsledek uložili do souboru setrideno.txt.

Dosud jsme pracovali pouze se standardním vstupem a výstupem, ale co chybový výstup (stderr)? Ten můžeme přesměrovat takto:

  [michal@griffon ~]$ cp work/* /tmp 2> chyby.txt

Tento příkaz zkopíruje obsah podadresáře work do adresáře /tmp a veškeré chybové hlášky uloží do souboru chyby.txt.

Roury

Nyní se dostáváme ke tmelu, který umožňuje propojit jednotlivé unixové utility do složitějších funkčních celků. Roura je de facto pojítkem mezi dvěma programy v tom smyslu, že standardní výstup jednoho přesměruje na standardní vstup druhého. Nejtypičtější a nejjednodušší příklad by byl použití programu less, abyste si mohli prohlédnout delší výpis programu ls. To by se realizovalo takto:

  [michal@griffon ~]$ ls -l | less

Znáte-li program sort (viz výše), můžete jej napojit na výpis programu du, který vypisuje velikosti souborů (a adresářů). S vhodnými parametry získáte setříděný výpis (od největšího po nejmenší) velikosti domovských adresářů uživatelů:

  du -s /home/* | sort -nr

Ještě jednou, co tedy roura způsobí? Způsobí to, že výpis programu du (tedy jeho standardní výstup) pošle (na standardní vstup) programu sort. Ten příslušný výpis zpracuje (setřídí) a pošle opět na standardní výstup, v tomto případě už na naši obrazovku.

Zkusme další příklad. Program head nebo tail vám poslouží, abyste z nějakého výpisu získali začátek nebo konec. V tomto případě byste si mohli nechat vypsat pouze pět adresářů s největším obsahem:

  du -s /home/* | sort -nr | head -n 5

Nyní zkusme nějaký komplexnější příkaz:

  dd if=/dev/hda | gzip -c | ssh mike@base "dd of=~/dump"

Tenhle příkaz umožňuje poslat obsah blokového zařízení hda (primary master IDE zařízení - třeba pevný disk) přes síť zabezpečeným (šifrovaným) kanálem a uložit jeho obsah do souboru dump v domovském adresáři uživatele mike na vzdáleném počítači base. Před tím, než se data pošlou přes síť se v tomto případě zkomprimují pomocí programu gzip.

Z tohoto příkladu by mělo být jasné, jak je v unixových systémech všechno pěkně propojeno. Jednotlivé unixové nástroje dělají jen jednu věc, ale dělají ji dobře. Tyto nástroje lze pak propojit prostřednictvím příkazové řádky a kombinovat do různých funkčních celků. V unixových systémech také platí, že všechno je soubor, tedy i pevný disk. Unixové nástroje umí velmi dobře pracovat se soubory. Dvě vlastnosti unixových systémů, které se vhodně doplňují a umožňují „snadno“ realizovat to, k čemu je v jiných operačních systémech potřeba speciální (a zpravidla komerční) software.

Filtry

Filtry jsou jednoúčelové programy, které nějakým způsobem upravují data ze standardního vstupu a upravená data posílají na standardní výstup. Mohou je třídit, upravovat nebo propouštět jen určité řádky nebo vzory.

Filtr Činnost
sort setřídí řádky podle zadaných kritérií
uniq ze setříděných řádek odstraní duplicity
grep propouští pouze řádky obsahující určitý vzor či výraz
head zachytí pouze několik prvních řádků výstupu
tail zachytí pouze několik posledních řádků výstupu
tr „překládá“ znaky – může třeba provést konverzi velkých písmen na malá, apod.
sed tzv. „stream editor“, umožňuje různě upravovat jím procházející text
awk programovací jazyk zaměřený na filtrování
cut umožňuje „vyříznout“ kusy řádek
wc vrací počet slov (nebo počet řádek, použijeme-li parametr -l)

Pokud byste měli na výstupu nějakého programu řadu duplicitních řádek, hodí se vám program uniq, který duplicity odstraní. Tomuto programu musíte ale nejprve pomoci a duplicitní řádky dát k sobě. K tomu použijete nám známý program sort:

  ps auh | cut -f 1 -d\  | sort | uniq

Tento příkaz vypíše všechny uživatele, pod jejichž právy běží některé procesy. Jako základ byl použit program ps k vypsání všech procesů. Z jeho výstupu se nám hodí pouze první slovo na každé řádce. To představuje uživatele, pod jehož právy běží každý běžící proces. Pomocí filtru cut jsme „vyřízli“ pouze první pole, jako oddělovač jsme specifikovali mezeru. Všimněte si zpětného lomítka, který neutralizoval vliv mezery jako oddělovače parametrů. Následně jsme výpis setřídili programem sort a odstranili duplicity pomocí programu uniq.

Použití programu cut je vhodné použít tam, kde jsou jasně dané oddělovací znaky. Třeba v souboru /etc/passwd slouží jako oddělovač dvojtečka. Můžeme tedy snadno získat výchozí interpret příkazové řádky (shell) uživatele michal:

  grep michal /etc/passwd | cut -f 7 -d: 

Naopak tam, kde je výpis nějakým způsobem formátovaný a nelze se tedy spolehnout na oddělovací znaky, je vhodnější využít program awk následujícím způsobem:

  ps aux | awk '{ print $2 }'

Tento příkaz vypíše všechny PID běžících procesů. Ty se nachází ve druhém sloupci výpisu programu ps, proto ta dvojka. Kdybychom chtěli jiný sloupec, nahradili bychom toto číslo adekvátním pořadovým číslem zvoleného sloupce.

Dlužno dodat, že program ps umožňuje velmi přesně specifikovat výstupní formát svého výpisu, a proto není tento trik vyloženě nutné znát. Na stranu druhou, je snadnější použít tento zápis, pokud si ho pamatujete, než pátrat v manuálové stránce programu ps, jak vhodně formátovat jeho výstup, aby se na něj dal použít program cut.

Program sed umožňuje provádět sofistikovanější úpravy filtrovaného textu. Asi nejznámější je konstrukce pro nahrazení nějakého řetězce jiným:

  echo "Jdeme tam." | sed s/Jdeme/Nejdeme/

To je samozřejmě velmi primitivní příklad. Můžeme zkusit něco trošku složitějšího:

  grep michal /etc/passwd | sed s/bash/zsh/

Tento příkaz upraví řádku se záznamem uživatele michal v /etc/passwd tak, že změní jeho výchozí shell z Bashe na zsh.

K programům awk a sed a jejich použití se dají najít i celé knihy, které do podrobna rozebírají jejich možnosti. Ze své praxe však nejčastěji používám výše uvedené konstrukce.

Program tr umožňuje nahradit nějakou skupinu znaků jinou skupinou. Může třeba převést všechna malá písmena v nějakém výpisu na velká:

  [michal@griffon ~]$ echo "Ahoj" | tr [a-z] [A-Z]
  AHOJ

Vpomeňte si na zástupné znaky a význam hranatých závorek. Je možné provádět různé „překlady“, ale to už nechám na vaší fantazii.

Program wc (zkrácenina od „word count“) umí počítat slova nebo řádky v nějakém výpisu. Takže můžeme třeba velice snadno zjistit počet uživatelů v systému:

  wc -l /etc/passwd

Program wc ale samozřejmě umí pracovat i jako součást roury:

  grep bash /etc/passwd | wc -l

Jak správně tušíte, příkaz vypíše počet uživatelů, kteří mají jako výchozí shell nastavený bash.

Příkaz místo parametru

Někdy se dostanete do situace, kdy budete chtít jako parametr zadat výstup nějakého příkazu. Kupříkladu, budete chtít zabít všechny procesy uživatele brian. Program ps vám poskytne potřebné informace o PID jednotlivých procesů, které pak budete chtít předat programu kill. Ten je však očekává jako parametr. Co s tím?

  kill -9 `ps au | grep "brian" | awk '{print $1}'`

To, co uzavřete mezi znaky ` se provede nejdříve a jejich obsah se nahradí za výstup příslušného výrazu. V tomto případě se tedy nejprve provede příkaz ps, od něhož získáme příslušná PID, která se pak vloží na místo, kde je očekává program kill. Tento zápis je plně ekvivalentní s tímto:

  kill -9 $(ps au | grep "brian" | awk '{print $1}')

Kam dál

pokrocili/komandlajna/io_roury_filtry.txt · Poslední úprava: 2009/11/11 13:52 autor: Michal Dočekal
CC Attribution-Share Alike 3.0
www.chimeric.de Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0 PDF Export