Správnější by bylo říci, že stdin
, stdout
a stderr
jsou "I/O streamy" spíše než soubory. Jak jste si všimli, tyto entity nežijí v souborovém systému. Ale filozofie Unixu, pokud jde o I/O, je „všechno je soubor“. V praxi to opravdu znamená, že můžete používat stejné funkce a rozhraní knihovny (printf
,scanf
, read
, write
, select
, atd.), aniž byste se museli starat o to, zda je I/O stream připojen ke klávesnici, diskovému souboru, soketu, potrubí nebo nějaké jiné I/O abstrakci.
Většina programů potřebuje číst vstup, zapisovat výstup a protokolovat chyby, takže stdin
, stdout
a stderr
jsou pro vás předdefinovány jako pohodlí při programování. Toto je pouze konvence a operační systém to nevynucuje.
Obávám se, že vaše chápání je zcela obrácené. :)
Představte si „standardní vstup“, „standardní výstup“ a „standardní chyba“ z programu z perspektivy, ne z pohledu jádra.
Když program potřebuje tisknout výstup, normálně tiskne na "standardní výstup". Program obvykle tiskne výstup na standardní výstup s printf
, který tiskne POUZE na standardní výstup.
Když program potřebuje vytisknout informace o chybě (nemusí to být nutně výjimky, ty jsou konstruktem programovacího jazyka, vynuceným na mnohem vyšší úrovni), normálně vytiskne "standardní chybu". Normálně to dělá s fprintf
, který přijímá datový proud souborů pro použití při tisku. Proud souboru může být jakýkoli soubor otevřený pro zápis:standardní výstup, standardní chyba nebo jakýkoli jiný soubor, který byl otevřen s fopen
nebo fdopen
.
"standardní" se používá, když soubor potřebuje číst vstup pomocí fread
nebo fgets
nebo getchar
.
Kterýkoli z těchto souborů lze snadno přesměrovat z shellu takto:
cat /etc/passwd > /tmp/out # redirect cat's standard out to /tmp/foo
cat /nonexistant 2> /tmp/err # redirect cat's standard error to /tmp/error
cat < /etc/passwd # redirect cat's standard input to /etc/passwd
Nebo celá enchilada:
cat < /etc/passwd > /tmp/out 2> /tmp/err
Existují dvě důležitá upozornění:Za prvé, „standardní vstup“, „standardní výstup“ a „standardní chyba“ jsou pouze konvence. Jsou velmi silné konvence, ale je to všechno jen dohoda, že je velmi hezké mít možnost spouštět programy jako je tento:grep echo /etc/services | awk '{print $2;}' | sort
a mít standardní výstupy každého programu připojené ke standardnímu vstupu dalšího programu v kanálu.
Za druhé jsem uvedl standardní funkce ISO C pro práci se souborovými proudy (FILE *
objekty) -- na úrovni jádra jsou to všechny deskriptory souborů (int
odkazy na tabulku souborů) a operace na mnohem nižší úrovni, jako je read
a write
, které nedělají šťastné vyrovnávací paměti funkcí ISO C. Myslel jsem, že to bude jednoduché a použijem jednodušší funkce, ale přesto jsem si myslel, že byste měli znát alternativy. :)
Standardní vstup - toto je popisovač souboru který váš proces čte, aby od vás získal informace.
Standardní výstup - váš proces zapisuje konvenční výstup do tohoto popisovače souboru.
Standardní chyba - váš proces zapisuje diagnostický výstup do tohoto popisovače souboru.
To je asi tak hloupé, jak to dokážu :-)
Samozřejmě je to většinou konvencí. Pokud si přejete, nic vám nebrání zapisovat diagnostické informace na standardní výstup. Můžete dokonce úplně zavřít tři popisovače souborů a otevřít své vlastní soubory pro I/O.
Když se váš proces spustí, měl by již mít tyto úchyty otevřené a může z nich pouze číst a/nebo do nich zapisovat.
Ve výchozím nastavení jsou pravděpodobně připojeny k vašemu koncovému zařízení (např. /dev/tty
), ale shelly vám umožní nastavit spojení mezi těmito ovladači a konkrétními soubory a/nebo zařízeními (nebo dokonce kanály k jiným procesům) ještě před spuštěním vašeho procesu (některé možné manipulace jsou docela chytré).
Příkladem je:
my_prog <inputfile 2>errorfile | grep XYZ
který bude:
- vytvořte proces pro
my_prog
. - otevřete
inputfile
jako standardní vstup (popis souboru 0). - otevřete
errorfile
jako standardní chyba (soubor popisovač 2). - vytvořit další proces pro
grep
. - připojte standardní výstup
my_prog
na standardní vstupgrep
.
K vašemu komentáři:
Když otevřu tyto soubory ve složce /dev, jak to, že nikdy neuvidím výstup běžícího procesu?
Je to proto, že to nejsou normální soubory. Zatímco UNIX představuje vše jako soubor někde v souborovém systému, na nejnižších úrovních to tak není. Většina souborů v /dev
hierarchie jsou buď znaková nebo bloková zařízení, v podstatě ovladač zařízení. Nemají velikost, ale mají hlavní a vedlejší číslo zařízení.
Když je otevřete, jste připojeni k ovladači zařízení spíše než k fyzickému souboru a ovladač zařízení je dostatečně chytrý na to, aby věděl, že samostatné procesy by měly být zpracovávány samostatně.
Totéž platí pro Linux /proc
souborový systém. To nejsou skutečné soubory, jen přísně kontrolované brány k informacím jádra.
Jako doplněk k výše uvedeným odpovědím je zde shrnutí přesměrování:
EDIT:Tato grafika není úplně správná.
První příklad vůbec nepoužívá stdin, předává "hello" jako argument příkazu echo.
Na obrázku je také uvedeno, že 2>&1 má stejný účinek jako &>, nicméně
ls Documents ABC > dirlist 2>&1
#does not give the same output as
ls Documents ABC > dirlist &>
Je to proto, že &> vyžaduje soubor k přesměrování a 2>&1 jednoduše posílá stderr do stdout