it-swarm-eu.dev

Jak přesměrovat stderr do souboru

Při použití příkazu Nohup k zadání příkazu ke spuštění na pozadí se v terminálu objeví nějaký obsah.

cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

Chci tento obsah uložit do souboru.

400
André M. Faria

V Linuxu (a dalších OS) existují dva hlavní výstupní toky, standardní výstup (stdout) a standardní chyba (stderr). Chybové zprávy, stejně jako ty, které zobrazujete, jsou vytištěny na standardní chyby. Klasický operátor přesměrování (command > file) přesměrovává pouze standardní výstup, takže na terminálu se stále zobrazuje standardní chyba. Chcete-li přesměrovat také stderr, máte několik možností:

  1. Přesměrovat stdout do jednoho souboru a stderr do jiného souboru:

    command > out 2>error
    
  2. Přesměrování stdout do souboru (>out) a poté přesměrovat stderr na stdout (2>&1):

    command >out 2>&1
    
  3. Přesměrovat oba do souboru (to nepodporují všechny shelly, například bash a zsh jej podporují, ale sh a ksh nepodporují ):

    command &> out
    

Pro více informací o různých operátorech ovládání a přesměrování viz zde .

685
terdon

První věc, kterou je třeba poznamenat, je, že existuje několik způsobů, které závisí na vašem účelu a Shell, proto to vyžaduje mírné porozumění mnoha aspektům. Některé příkazy, jako například time a strace, ve výchozím nastavení zapisují výstup do stderr a mohou nebo nemusí poskytovat metodu přesměrování specifickou pro tento příkaz.

Základní teorie přesměrování spočívá v tom, že proces vytvořený Shellem (za předpokladu, že se jedná o externí příkaz a ne vestavěný Shell), je vytvořen pomocí fork() a execve() syscalls, a předtím, než se stane další syscall dup2() provede nezbytná přesměrování dříve, než se stane execve(). V tomto smyslu jsou přesměrování zděděna od mateřské Shell. m&>n A m>n.txt Informují Shell o tom, jak provést open() a dup2() syscall (viz také Jak funguje přesměrování vstup =, Jaký je rozdíl mezi přesměrováním a potrubím a Co & přesně znamená v přesměrování výstup )

Přesměrování skořepiny

Nejtypičtější je přes 2> V Bourne-like shelly , jako je dash (což je symlinked to /bin/sh ) a bash; první je výchozí prostředí a prostředí kompatibilní s POSIX a druhým je to, co většina uživatelů používá pro interaktivní relaci. Liší se syntaxí a funkcemi, ale naštěstí pro nás přesměrování chybového toku funguje stejně (s výjimkou nestandardního &>). V případě csh a jeho derivátů přesměrování stderru tam nefunguje úplně.

Vraťme se k části 2>. Je třeba si všimnout dvou klíčových věcí: > Znamená operátor přesměrování, kde otevřeme soubor a celé číslo 2 Znamená desderr file deskriptor; ve skutečnosti přesně takto standard POSIX pro jazyk Shell definuje přesměrování v oddíl 2.7 :

[n]redir-op Word

Pro jednoduché přesměrování > Se pro stdout předpokládá celé číslo 1, Tj. echo Hello World > /dev/null Je stejné jako echo Hello World 1>/dev/null. Všimněte si, že operátor celého čísla nebo přesměrování nelze citovat, jinak je Shell jako takové nerozpozná, a místo toho zachází jako s literálním řetězcem textu. Pokud jde o mezery, je důležité, aby celé číslo bylo hned vedle operátora přesměrování, ale soubor může být buď vedle operátora přesměrování, nebo ne, tj. command 2>/dev/null A command 2> /dev/null Budou fungovat dobře.

Trochu zjednodušená syntaxe typického příkazu v Shell by byla

 command [arg1] [arg2]  2> /dev/null

Trik je v tom, že přesměrování se může objevit kdekoli. To platí jak 2> command [arg1], Tak command 2> [arg1]. Všimněte si, že pro bash Shell existuje &> Způsob, jak přesměrovat jak stdout, tak stderr proudy současně, ale znovu - je to bash specifické a pokud usilujete o přenositelnost skriptů, nemusí to fungovat. Viz také buntu Wiki a Jaký je rozdíl mezi &> a 2> & 1 .

Poznámka: Operátor přesměrování > zkrátí soubor a přepíše jej, pokud soubor existuje. 2>> Může být použit pro připojení stderr k souboru.

Pokud si všimnete, > Je určen pro jeden jediný příkaz. U skriptů můžeme přesměrovat stderr stream celého skriptu zvenčí jako v myscript.sh 2> /dev/null Nebo můžeme využít exec vestavěný . Vestavěný program exec má schopnost přepojit proud pro celou relaci Shell, ať už interaktivně nebo skriptem. Něco jako

#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file

V tomto příkladu by měl soubor protokolu zobrazovat stat: cannot stat '/etc/non_existing_file': No such file or directory.

Ještě jiným způsobem je funkce. Jak ve své odpovědi uvedl kopciuszek , můžeme napsat funkční deklaraci s již připojeným přesměrováním, to znamená

some_function(){
    command1
    command2
} 2> my_log_file.txt

Příkazy výhradně pro stderr

Příkazy jako time a strace ve výchozím nastavení zapíší svůj výstup do stderr. V případě příkazu time je jedinou schůdnou alternativou přesměrovat výstup celého příkazu, tj

time echo foo 2>&1 > file.txt

alternativně lze synchronní seznam nebo podshell přesměrovat, pokud chcete oddělit výstup (jak ukazuje související příspěvek ):

{ time sleep 1 2> sleep.stderr ; } 2> time.txt

Jiné příkazy, například strace nebo dialog, poskytují prostředky pro přesměrování stderr. strace má možnost -o <filename.txt>, která umožňuje určit název souboru, kam má být výstup zapsán. Existuje také možnost zápisu textového souboru pro každý podproces, který strace vidí. Příkaz dialog zapíše textové uživatelské rozhraní do stdout, ale výstup do stderr, takže za účelem ložit jeho výstup do proměnné (protože var=$(...) a potrubí pouze stderr ) musíme vyměnit deskriptory souborů

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);

ale navíc existuje vlajka --output-fd, kterou můžeme také využít. Existuje také metoda pojmenovaných dýmek. Doporučuji, abyste si přečetli propojený příspěvek o příkazu dialog, kde najdete podrobný popis událostí.

21