Como canalizar stderr sem stdout de tubulação

23

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

Eu sei que este comando funciona, mas também escreve o padrão.

Command 2>&1 | tee -a $LOG

Como obtenho apenas o erro padrão?

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

    
por C. Ross 09.09.2009 / 12:48

4 respostas

24

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 Cria um novo descritor de arquivo, 3 uma duplicata (cópia) de fd 1 (stdout).

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

2>&3 Faça o fd 2, uma duplicata (cópia) de 3, que anteriormente era uma cópia da stdout.

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

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

    
por 09.09.2009 / 12:55
12

O comando Unix / Linux do Kyle faz o trabalho de trocar o STDERR pelo STDOUT; no entanto, a explicação não está correta. Os operadores de redirecionamento não fazem cópia nem 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 exibiria um erro porque & 3 ainda não existe, pois está localizado antes de 3 > & 1. 3 > alguma coisa é uma maneira de declarar (definir) que vamos usar um terceiro tubo, então ele deve estar localizado antes de fluirmos água para aquele tubo, por exemplo, como Kyle o escreveu. Tente esta outra maneira 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 vergonha. Você não pode fazer coisas como "3 > & 1 3 > & 2" no mesmo comando, porque o Linux usará somente o primeiro encontrado e descartará o segundo.

Eu 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. Para instace, eu tenho uma tarefa cron que eu quero que ambas as saídas (erro e padrão) vão para um arquivo de log e deixe o erro também sair para fazer uma mensagem de e-mail enviada para o 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 de resolver o problema:

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

Note que eu tenho que usar log1 duas vezes e eu tenho que acrescentar em ambos os casos, o primeiro usando a opção "-a" para o comando "tee" e o segundo usando "> >".

Fazendo um cat log1 você recebe o seguinte:

STD1
STD2
-bash: sdfr: command not found

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

    
por 19.11.2010 / 18:47
2

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

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

i.e. dup stderr para stdout, redireciona o stdout para / dev / null e, em seguida, canaliza para 'cat -n'

funciona no pdksh no meu sistema:

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

$ errorecho foo
foo

$ errorecho foo >/dev/null   # should still display even with stdout redirected
foo

$ errorecho foo 2>&1 >/dev/null | cat -n
     1  foo
$   
    
por 09.09.2009 / 21:46
1

eu comecei a funcionar como você sempre quis, pois eu também precisava disso e refinava seu comando. agora para mim funciona corretamente usando o bash 3.2 no debian squeeze usando isto

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

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

    
por 12.02.2013 / 15:23