stdin, stdout a stderr jsou tři datové toky vytvořené při spuštění příkazu Linuxu. Můžete je použít ke zjištění, zda jsou vaše skripty přenášeny nebo přesměrovány. Ukážeme vám jak.
Table of Contents
Streamy spojují dva body
Jakmile se začnete učit o Linuxu a operačních systémech podobných Unixu, setkáte se s pojmy stdin, stdout a stederr. Tyto jsou tři standardní proudy které se vytvoří při spuštění příkazu Linuxu. V oblasti výpočetní techniky je tok něco, co může přenášet data. V případě těchto datových proudů jsou těmito daty text.
Datové toky, stejně jako vodní toky, mají dva konce. Mají zdroj a odtok. Kterýkoli příkaz Linuxu, který používáte, poskytuje jeden konec každého streamu. Druhý konec je určen shellem, který spustil příkaz. Tento konec bude připojen k oknu terminálu, připojen k potrubí nebo přesměrován na soubor nebo jiný příkaz podle příkazového řádku, který příkaz spustil.
Standardní streamy Linuxu
V Linuxu je standardním vstupním tokem stdin. Toto přijímá text jako svůj vstup. Textový výstup z příkazu do shellu je dodáván prostřednictvím proudu stdout (standardní výstup). Chybové zprávy z příkazu jsou odesílány prostřednictvím proudu stderr (standardní chyba).
Můžete tedy vidět, že existují dva výstupní proudy, stdout a stderr, a jeden vstupní proud, stdin. Protože chybová hlášení a normální výstup mají každý svůj vlastní kanál, který je přenáší do okna terminálu, lze je zpracovávat nezávisle na sobě.
S proudy se zachází jako se soubory
Se streamy se v Linuxu – jako téměř se vším ostatním – zachází, jako by to byly soubory. Můžete číst text ze souboru a můžete jej zapisovat do souboru. Obě tyto akce zahrnují proud dat. Koncepce manipulace s proudem dat jako se souborem tedy není tak složitá.
Každému souboru přidruženému k procesu je přiděleno jedinečné číslo pro jeho identifikaci. Toto je známé jako deskriptor souboru. Kdykoli je vyžadováno provedení akce se souborem, deskriptor souboru slouží k identifikaci souboru.
Tyto hodnoty se vždy používají pro stdin, stdout a stderr:
0: stdin
1: stdout
2: stderr
Reakce na potrubí a přesměrování
Abychom někomu usnadnili úvod do předmětu, běžnou technikou je vyučovat zjednodušenou verzi tématu. Například u gramatiky je nám řečeno, že pravidlo je „já před E, kromě po C“. Ale ve skutečnosti tam je více výjimek z tohoto pravidla než jsou případy, které se tomu podřizují.
V podobném duchu, když mluvíme o stdin, stdout a stderr, je vhodné vyslovit přijatý axiom, že proces ani neví, ani se nestará, kde jsou jeho tři standardní toky ukončeny. Má se proces starat o to, zda jeho výstup jde do terminálu nebo je přesměrován do souboru? Dokáže dokonce zjistit, zda jeho vstup přichází z klávesnice nebo je do něj přenášen z jiného procesu?
Proces ve skutečnosti ví – nebo alespoň může zjistit, pokud se rozhodne zkontrolovat – a může podle toho změnit své chování, pokud se autor softwaru rozhodl tuto funkci přidat.
Tuto změnu chování vidíme velmi snadno. Zkuste tyto dva příkazy:
ls
ls | cat
Příkaz ls se chová odlišně, pokud je jeho výstup (stdout) přenášen do jiného příkazu. Je to ls, který přepíná na výstup jednoho sloupce, nejedná se o konverzi prováděnou cat. A ls dělá to samé, pokud je jeho výstup přesměrován:
ls > capture.txt
Přesměrování stdout a stderr
Výhoda chybových zpráv doručovaných vyhrazeným streamem. To znamená, že můžeme přesměrovat výstup příkazu (stdout) do souboru a stále vidět chybové zprávy (stderr) v okně terminálu. V případě potřeby můžete na chyby reagovat, jakmile se vyskytnou. Také to zabrání tomu, aby chybové zprávy kontaminovaly soubor, do kterého byl stdout přesměrován.
Zadejte následující text do editoru a uložte jej do souboru s názvem error.sh.
#!/bin/bash echo "About to try to access a file that doesn't exist" cat bad-filename.txt
Udělejte skript spustitelný pomocí tohoto příkazu:
chmod +x error.sh
První řádek skriptu odešle text do okna terminálu prostřednictvím proudu stdout. Druhý řádek se pokusí získat přístup k neexistujícímu souboru. Tím se vygeneruje chybová zpráva doručená prostřednictvím stderr.
Spusťte skript pomocí tohoto příkazu:
./error.sh
Vidíme, že oba výstupní proudy, stdout a stderr, byly zobrazeny v oknech terminálu.
Zkusme přesměrovat výstup do souboru:
./error.sh > capture.txt
Výstup z stdin byl přesměrován do souboru podle očekávání.
Symbol > přesměrování standardně funguje se stdout. K označení standardního výstupního proudu, který chcete přesměrovat, můžete použít jeden z číselných deskriptorů souborů.
Chcete-li explicitně přesměrovat stdout, použijte tuto instrukci pro přesměrování:
1>
Chcete-li explicitně přesměrovat stderr, použijte tuto instrukci pro přesměrování:
2>
Zkusme náš test znovu a tentokrát použijeme 2>:
./error.sh 2> capture.txt
Zpráva stderr je podle očekávání v souboru capture.txt.
Přesměrování stdout i stderr
Jistě, pokud můžeme přesměrovat buď stdout nebo stderr do souboru nezávisle na sobě, měli bychom být schopni přesměrovat je oba současně, do dvou různých souborů?
Ano, můžeme. Tento příkaz přesměruje stdout do souboru s názvem capture.txt a stderr do souboru s názvem error.txt.
./error.sh 1> capture.txt 2> error.txt
Pojďme zkontrolovat obsah každého souboru:
cat capture.txt
cat error.txt
Přesměrování stdout a stderr do stejného souboru
To je úhledné, každý ze standardních výstupních toků jde do vlastního vyhrazeného souboru. Jedinou další kombinací, kterou můžeme udělat, je odeslat stdout i stderr do stejného souboru.
Toho můžeme dosáhnout pomocí následujícího příkazu:
./error.sh > capture.txt 2>&1
Pojďme to rozebrat.
./error.sh: Spustí soubor skriptu error.sh.
> capture.txt: Přesměruje stdout stream do souboru capture.txt. > je zkratka pro 1>.
2>&1: Používá instrukci přesměrování &>. Tato instrukce vám umožňuje říct shellu, aby se jeden proud dostal do stejného cíle jako jiný proud. V tomto případě říkáme „přesměrovat stream 2, stderr, do stejného cíle, na který je přesměrován stream 1, stdout.“
Zkontrolujeme soubor capture.txt a uvidíme, co je v něm.
cat capture.txt
Proudy stdout i stderr byly přesměrovány do jediného cílového souboru.
Chcete-li mít výstup streamu přesměrován a tiše zahozen, nasměrujte výstup do /dev/null.
Detekce přesměrování v rámci skriptu
Diskutovali jsme o tom, jak může příkaz zjistit, zda je některý z proudů přesměrován, a podle toho se může rozhodnout změnit své chování. Můžeme toho dosáhnout v našich vlastních skriptech? Ano, můžeme. A je to velmi snadná technika na pochopení a použití.
Zadejte následující text do editoru a uložte jej jako input.sh.
#!/bin/bash if [ -t 0 ]; then echo stdin coming from keyboard else echo stdin coming from a pipe or a file fi
K tomu, aby byl spustitelný, použijte následující příkaz:
chmod +x input.sh
Chytrá část je test v hranatých závorkách. Volba -t (terminál) vrátí hodnotu true (0), pokud je soubor přidružen k deskriptoru souboru končí v okně terminálu. Jako argument testu jsme použili deskriptor souboru 0, který představuje stdin.
Pokud je stdin připojen k oknu terminálu, test se ukáže jako pravdivý. Pokud je stdin připojen k souboru nebo kanálu, test se nezdaří.
Ke generování vstupu do skriptu můžeme použít jakýkoli vhodný textový soubor. Zde používáme soubor s názvem dummy.txt.
./input.shThe output shows that the script recognizes that the input isn’t coming from a keyboard, it is coming from a file. If you chose to, you could vary your script’s behavior accordingly.
That was with a file redirection, let’s try it with a pipe.
cat dummy.txt | ./input.shSkript rozpozná, že je do něj přenášen jeho vstup. Přesněji řečeno, znovu rozpozná, že proud stdin není připojen k oknu terminálu.
Spusťte skript bez potrubí ani přesměrování.
./input.shTok stdin je připojen k oknu terminálu a skript to odpovídajícím způsobem hlásí.
Abychom totéž zkontrolovali s výstupním proudem, potřebujeme nový skript. Zadejte následující text do editoru a uložte jej jako output.sh.
#!/bin/bash if [ -t 1 ]; then echo stdout is going to the terminal window else echo stdout is being redirected or piped fiK tomu, aby byl spustitelný, použijte následující příkaz:
chmod +x input.shJediná podstatná změna tohoto skriptu je v testu v hranatých závorkách. Pro reprezentaci deskriptoru souboru pro stdout používáme číslici 1.
Pojďme to zkusit. Výstup zavedeme přes kočku.
./output | catSkript rozpozná, že jeho výstup nesměřuje přímo do okna terminálu.
Skript můžeme také otestovat přesměrováním výstupu do souboru.
./output.sh > capture.txtNeexistuje žádný výstup do okna terminálu, jsme tiše vráceni do příkazového řádku. Jak bychom očekávali.
Můžeme se podívat do souboru capture.txt, abychom viděli, co bylo zachyceno. Použijte k tomu následující příkaz.
cat capture.shJednoduchý test v našem skriptu opět detekuje, že stdout stream není odesílán přímo do okna terminálu.
Pokud skript spustíme bez jakýchkoli kanálů nebo přesměrování, měl by detekovat, že stdout je doručován přímo do okna terminálu.
./output.shA to je přesně to, co vidíme.
Proudy Vědomí
Vědět, jak zjistit, zda jsou vaše skripty připojeny k oknu terminálu, potrubí nebo jsou přesměrovány, vám umožňuje odpovídajícím způsobem upravit jejich chování.
Protokolování a diagnostický výstup může být více či méně podrobný v závislosti na tom, zda jde na obrazovku nebo do souboru. Chybová hlášení mohou být protokolována do jiného souboru, než je běžný výstup programu.
Jak už to tak bývá, více znalostí přináší více možností.