Com o bash, como posso direcionar o erro padrão para outro processo?

137

É bem conhecido como canalizar a saída padrão de um processo para outra entrada padrão de processos:

proc1 | proc2

Mas e se eu quiser enviar o erro padrão de proc1 para proc2 e deixar a saída padrão indo para o local atual? Você pensaria que bashteria um comando ao longo das linhas de:

proc1 2| proc2

Mas, infelizmente, não. Há alguma maneira de fazer isso?

paxdiablo
fonte
Você pode fazer um redirecionamento tão simples rc, que é outro shell. Por exemplo: proc1 |[2] proc2. Não é legal? Não no bashentanto.
Rolf

Respostas:

168

Também há substituição de processo . O que faz com que um processo substitua um arquivo.
Você pode enviar stderrpara um arquivo da seguinte maneira:

process1 2> file

Mas você pode substituir um processo pelo arquivo da seguinte maneira:

process1 2> >(process2)

Aqui está um exemplo concreto que envia stderrpara a tela e anexa a um arquivo de log

sh myscript 2> >(tee -a errlog)
Scot
fonte
23
Isso responde corretamente à pergunta indicada e deve ser a resposta aceito por @paxdiablo
mmlb
Eu tentei isso. Não funcionou ( weston --help 2> >(less)), e ele quebrou o meu escudo, eu tinha que sair e fazer login novamente.
Rolf
1
@Rolf se ambos weston --helpe lessestão esperando para ter uma interação teclado, mas apenas 1 deles recebe, então você pode estar em uma situação embaraçosa. Tente fazer testes com algo parecido grep. Além disso, você pode achar que as duas entradas de mouse / teclado estão indo para o segundo comando de qualquer maneira, e não para weston.
BeowulfNode42
88

Você pode usar o seguinte truque para trocar stdout e stderr. Então você apenas usa a funcionalidade de canal regular.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Fornecido stdoute stderrambos apontaram para o mesmo lugar no início, isso vai lhe dar o que você precisa.

O que o x>ybit faz é alterar o identificador de arquivo, xpara que ele agora envie suas informações para onde o identificador de arquivo yaponta atualmente. Para o nosso caso específico:

  • 3>&1cria um novo identificador 3que será exibido no identificador atual1 (stdout original), apenas para salvá-lo em algum lugar para o marcador final abaixo.
  • 1>&2modifica o identificador 1(stdout) para enviar para o identificador atual2 (stderr original).
  • 2>&3-modifica o identificador 2(stderr) para enviar para o identificador atual3 (stdout original) e depois fecha o identificador 3(via -no final).

É efetivamente o comando swap que você vê nos algoritmos de classificação:

temp   = value1;
value1 = value2;
value2 = temp;
paxdiablo
fonte
3
Qual é o valor de usar 1>&2-aqui e não apenas 1>&2? Não entendo por que queremos fechar o fd 2, se vamos apenas reabrir / reatribuí-lo imediatamente.
dubiousjim
1
@dubiousjim, nenhuma vantagem nesse caso em particular, eu suspeito que fiz isso apenas para ser consistente - fechar o identificador de arquivo 3 é uma boa idéia para liberá-lo.
paxdiablo
Bom ponto, @ovgolovin, não acredito que ninguém tenha percebido isso em sete meses desde que fiz essa edição. Corrigido conforme sua sugestão.
precisa
tentando fazer o make do gcc (que é colorido no meu sistema) funcionar com isso "(make 3> & 1 1> & 2-2> & 3-) | less -R" while "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "funciona conforme o esperado.
sincronizado
Parece que suas explicações estão de volta para a frente nos dois segundos redirecionamentos. 1> & 2- define o identificador de arquivo 2 (stderr original) para manipular 1 (stdout original) 2> & 3- define o identificador de arquivo 3 (stdout copiado) para manipular 2 (stderr original). Por favor, corrija-me se eu estiver errado. btw, eu acho que o traço no 2 é para impedir que novos dados stderr sejam enviados para esse buffer enquanto ele está sendo preenchido com os dados do stdout.
aghsmith
70

O Bash 4 possui este recurso:

Se `| & 'for usado, o erro padrão do comando1 será conectado à entrada padrão do comando2 através do pipe; é uma abreviação de 2> & 1 |. Esse redirecionamento implícito do erro padrão é executado após qualquer redirecionamento especificado pelo comando.

O zsh também possui esse recurso.

-

Com outras conchas / mais antigas, insira isso explicitamente como

FirstCommand 2> & 1 | OtherCommand

Pausado até novo aviso.
fonte
14
Ao ler os documentos, isso gera erro e saída padrão, em vez de apenas stderr, mas é bom saber. Hora de começar a olhar para o bash 4, eu acho.
paxdiablo
O manual atual do bash lê "Se | & é usado, o erro padrão do comando, além de sua saída padrão, é conectado à entrada padrão do command2". Isso explicitamente não é o que o OP deseja.
Peter - Restabelece Monica
@ PeterA.Schneider: O OP diz "deixe a saída padrão indo para a sua localização atual", o que pode ser ambíguo.
Pausado até novo aviso.
Não estou conseguindo ver nenhuma ambiguidade. Sua sugestão (1) funde os dois fluxos. (2) OtherCommandescreve os dados combinados em algum lugar, possivelmente em outro lugar. Portanto, não são os mesmos dados e estão potencialmente indo para outro lugar. Isso é exatamente o oposto do desejo do OP, não é?
Peter - Restabelece Monica
@ PeterA.Schneider: Onde mais fica a localização atual da saída padrão? Se as proc1saídas para stdout e stderr e você deseja que o stderr vá para o stdin de proc2(que é o local para onde o stdout do proc1 está indo), minha resposta é essa. Dei ao OP o que ele pedia , talvez não o que ele pretendia pedir. Aí reside a ambiguidade potencial. O OP aceitou a resposta que troca stdout e stderr, que não é o que ele pediu.
Pausado até novo aviso.
27

A troca é excelente, pois resolve o problema. Caso você nem precise do stdout original, faça-o desta maneira:

proc1 2>&1 1>/dev/null | proc2

A ordem é vital; você não iria querer:

proc1 >/dev/null 2>&1 | proc1

Como isso irá redirecionar tudo para /dev/null!

kccqzy
fonte
0

Nenhuma delas realmente funcionou muito bem. A melhor maneira que eu encontrei de fazer o que você queria é:

(command < input > output) 2>&1 | less

Isso funciona apenas para casos em commandque não precisa de entrada do teclado. por exemplo:

(gzip -d < file.gz > file) 2>&1 | less

colocaria erros de gzip em menos

sbingner
fonte