Jsem v Linuxu nováčkem a snažím se pochopit, jak fungují přesměrování.
Testoval jsem různé syntaxe pro přesměrování stdout
a stderr
do stejného souboru, které nedávají všechny stejné výsledky.
Pokud se například pokusím vypsat 2 soubory, které neexistují (file1
a file2
) a 2, které ano (foo
a fz
):
Syntaxe č. 1 (bez přesměrování):
$ ls file1 foo fz file2
Zde je výstup, který dostanu do terminálu:
ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo fz
Syntaxe č. 2:
Nyní s přesměrováním:
$ ls file1 foo fz file2 > redirect 2>&1
redirect
soubor obsahuje totéž jako výsledek pro syntaxi #1:
ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz
S oběma výše uvedenými syntaxemi se tedy zdá, že shell vypíše stderr
nejprve, potom stdout
.
Syntaxe č. 3:
Nyní, když to zkusím s některou z následujících syntaxí:
$ ls file1 foo fz file2 > redirect 2> redirect
nebo
$ ls file1 foo fz file2 2> redirect > redirect
Poté redirect
soubor bude obsahovat toto:
foo
fz
nnot access file1: No such file or directory
ls: cannot access file2: No such file or directory
Tady to vypadá jako stdout
je vytištěno před stderr
, ale pak vidíme, že začátek stderr
je „oříznuto“ o stejný počet znaků jako stdout
.
stdout
má 6 znaků (foo fz
, včetně návratu vozíku), tedy prvních 6 znaků z stderr
(ls: ca
) byly přepsány stdout
.
Takže to vlastně vypadá jako stderr
byl vytištěn jako první, a to stdout
byl poté vytištěn přes stderr
místo toho, aby k němu byl připojen.
Větší smysl by mi však dávalo, kdyby stderr
byl úplně smazáno a nahrazeno stdout
, spíše než jen částečně přepsaný.
Syntaxe č. 4:
Jediný způsob, jak jsem našel, jak opravit syntaxi #3, je přidání operátoru append do stdout
:
$ ls file1 foo fz file2 >> redirect 2> redirect
nebo
$ ls file1 foo fz file2 2> redirect >> redirect
Což vytváří totéž jako syntaxe #2:
ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz
Tento článek vysvětluje, že syntaxe #3 je chybná (pravděpodobně i syntaxe #4). Ale pro argumentaci:proč je syntaxe #3 špatná? Co přesně říká (nebo ne telling) shell dělat na rozdíl od syntaxe #2?
Související:Jaký je rozdíl mezi $(…) a `…` v Bash?
Existuje také důvod, proč se na výstupu vždy zobrazuje stderr
před stdout
?
Děkuji!
Přijatá odpověď:
Je to jako spouštění dvou procesů pro zápis do stejného souboru současně… špatný nápad. Skončíte se dvěma různými popisovači otevřených souborů a vaše data mohou být zkomolená (jak je tomu v bodě 3 výše). Použití syntaxe #2 je správné; to dělá jednu popisovač souboru a ukazuje stderr i stdout na stejné místo.
Pokud jde o stderr, který se vždy tiskne jako první, neexistuje na to žádné pravidlo. Mám podezření, že s ls
je to proto, že ls
potřebuje zkontrolovat každý záznam v adresáři, než může skutečně uvést, že konkrétní soubor neexistuje. Takže místo toho, aby provedl N průchodů přes adresářovou tabulku, provede jeden průchod, zkontroluje všechny zadané argumenty příkazového řádku, nahlásí chyby a vytiskne nalezené soubory. Jiné příkazy se mohou tisknout do stderr po stdout nebo je dokonce střídat.