Como canalizar stderr sem canalizar stdout

24

Como canalizar o fluxo de erro padrão sem canalizar o fluxo de saída padrão?

Eu sei que esse comando funciona, mas também grava o padrão.

Command 2>&1 | tee -a $LOG

Como obtenho apenas o erro padrão?

Nota: O que eu quero disso é apenas gravar o fluxo stderr em um log e gravar stderr e stdout no console.

Cruz
fonte

Respostas:

26

Para fazer isso, use um descritor de arquivo extra para alternar stderr e stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

Basicamente, funciona, ou pelo menos acho que funciona, da seguinte forma:
As re-direções são avaliadas da esquerda para a direita.

3>&1 Torna um novo descritor de arquivo 3 uma duplicata (cópia) do fd 1 (stdout).

1>&2 Faça do stdout (1) uma duplicata do fd 2 (stderr)

2>&3 Faça fd 2, uma duplicata (cópia) de 3, que foi previamente copiada do stdout.

Então agora stderr e stdout estão trocados.

| tee foo.file tee duplica o descritor de arquivo 1, que foi transformado em stderr.

Kyle Brandt
fonte
Oh, não testada com ksh, trabalha com o bash embora ...
Kyle Brandt
Obrigado, funciona em ksh também. Eu acho que a maioria das coisas de pipe e stream são padrão posix.
9389 C. Ross
"Copiar" não está realmente correto - Veja a resposta de @ Guasqueño.
Kyle Brandt
Isso também funciona no Windows com tee.exe:) instalado
Acorn
13

O comando Unix / Linux de Kyle faz o trabalho de alternar o STDERR com o STDOUT; no entanto, a explicação não está certa. Os operadores de redirecionamento não fazem nenhuma cópia ou duplicação, apenas redirecionam o fluxo para uma direção diferente.

Reescrever o comando de Kyle movendo temporariamente o 3> & 1 para o final, facilitaria a compreensão do conceito:

find /var/log  1>&2  2>&3  3>&1  

Escrito desta maneira, porém, o Linux exibirá um erro porque o & 3 ainda não existe, pois está localizado antes do 3> & 1. 3> Algo é uma maneira de declarar (definir) que vamos usar um terceiro tubo, então ele precisa ser localizado antes de colocarmos água nesse tubo, por exemplo, como Kyle o escreveu. Tente este outro caminho apenas por diversão:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

Não ter uma maneira de fazer cópias é uma pena. Você não pode fazer coisas como "3> & 1 3> & 2" no mesmo comando, porque o Linux usará apenas o primeiro encontrado e dispensa o segundo.

Ainda não encontrei uma maneira de enviar o erro e a saída regular para um arquivo e também enviar uma cópia do erro para a saída padrão com um comando. Por exemplo, tenho um trabalho cron em que desejo que as duas saídas (erro e padrão) sejam enviadas para um arquivo de log e deixem que o erro também apareça para fazer uma mensagem de email enviada ao meu blackBerry. Eu posso fazer isso com dois comandos usando "tee", mas o erro não aparece na ordem correta entre a linha de saída regular no arquivo. Esta é a maneira feia que eu resolvi o problema:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Observe que eu tenho que usar log1 duas vezes e preciso acrescentar nos dois casos, o primeiro usando a opção "-a" para o comando "tee" e o segundo usando ">>".

Ao fazer um log1 de gato, você obtém o seguinte:

STD1
STD2
-bash: sdfr: command not found

Observe que o erro não aparece na segunda linha como deveria.

Guasqueño
fonte
Correção impressionante !
Kyle Brandt
Confira zsh e mult_iosopção ( ativada por padrão) para poder redirecionar um FD várias vezes.
Tom Hale
2

de acordo com a página de manual do ksh (pdksh), você pode:

Comando 2> & 1> / dev / null | gato -n

ou seja, dup stderr para stdout, redirecione stdout para / dev / null e depois entre em 'cat -n'

funciona no pdksh no meu sistema:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
foo

$ errorecho foo> / dev / null # ainda deve ser exibido mesmo com o stdout redirecionado
foo

$ errorecho foo 2> & 1> / dev / null | gato -n
     1 foo
$   
cas
fonte
Também trabalha com o BusyBox
Udo G
1

Eu consegui rodar como você sempre quis, já que eu também precisava e refinei seu comando. Agora, para mim, ele funciona corretamente usando o bash 3.2 no debian squeeze usando este

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

enquanto o log1 registra stdout e stderr e log2 registra apenas stderr e nada mais é colocado na tela.

martinseener
fonte