Tubulação STDERR vs. STDOUT

24

De acordo com " Linux: a referência completa, 6ª edição " (pág. 44), você pode canalizar apenas o STDERR usando os |&símbolos de redirecionamento.

Eu escrevi um script bastante simples para testar isso:

#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2

Eu executo esse script assim:

./script.sh |& sed 's:^:\t:'

Presumivelmente, apenas as linhas impressas em STDERR serão recuadas. No entanto, ele realmente não funciona assim, como eu vejo:

    Normal Text.
    Error Text. 

O que eu estou fazendo errado aqui?

Naftuli Kay
fonte

Respostas:

26

Não sei qual texto seu livro usa, mas o manual do bash é claro (se você já conhece um pouco os redirecionamentos):

E se |& usado, o erro padrão do command1, além de sua saída padrão, é conectado à entrada padrão do command2 através do pipe; é uma abreviação de 2>&1 |. Esse redirecionamento implícito do erro padrão para a saída padrão é executado após qualquer redirecionamento especificado pelo comando.

Portanto, se você não deseja misturar saída padrão e erro padrão, precisará redirecionar a saída padrão para outro lugar. Vejo Como grep fluxo de erro padrão (stderr)?

{ ./script.sh 2>&1 >&3 | sed 's:^:\t:'; } 3>&1

Os fd 1 e 3 de script.shesed apontarão para o destino stdout original no entanto. Se você quer ser um bom cidadão, pode fechar o fd 3 que esses comandos não precisam:

{ ./script.sh 2>&1 >&3 3>&- | sed 's:^:\t:' 3>&-; } 3>&1

bashe ksh93pode condensar o >&3 3>&-para >&3-(movimento de fd).

Gilles 'SO- parar de ser mau'
fonte
O manual do bash não está totalmente claro para mim. Eu não entendo muito bem porque smth como ./script.sh > /tmp/stdout_goes_here |& grep 'grepping_script_stderr'não funcionar conforme pretendido, ou seja: redirecionamento script.sh's stdout(o que, de acordo com o trecho manual deve acontecer primeiro), em seguida, permitir grepprocessar o script de stderr. Em vez disso, stderre tdout` terminam emstdout_goes_here
sxc731 11/11
1
@ sxc731 |&é mais curto para 2>&1 |. Então, >/tmp/stdout_goes_here |&redireciona o stdout para /tmp/stdout_goes_here, em seguida, 2>&1redireciona o stderr para onde quer que o stdout esteja, o que é /tmp/stdout_goes_here, e finalmente |não recebe nenhuma entrada porque a saída do comando foi redirecionada. Lembre-se de que >&1redireciona para onde quer que o descritor de arquivos 1 esteja indo atualmente , e não para onde quer que o descritor de arquivos 1 acabe indo . Para canalizar apenas o stderr e redirecionar o stdout para um arquivo, é uma maneira 2>&1 >/tmp/stdout_goes_here |.
Gilles 'SO- stop be evil'
6

|&pipes stderr para stdin, como 2>&1 |, então o próximo programa terá ambos no stdin.

$cat test.sh
#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2
$./test.sh | sed 's:^:\t:'
Error Text.
        Normal Text.
$ ./test.sh |& sed 's:^:\t:'
        Normal Text.
        Error Text.
Kevin
fonte
Ah, então é basicamente equivalente à expressão mais longa runcommand 2>&1 | tee? ie runcommand |& tee?
Naftuli Kay
sim, são iguais.
Kevin
1

|&no bash é apenas um atalho (não terrivelmente portátil) para 2>&1 |, então você deve ver todas as linhas recuadas.

jw013
fonte