Eu tenho um programa que grava informações no stdout
e stderr
, e preciso passar grep
pelo que está chegando ao stderr , apesar de desconsiderar o stdout .
Claro que posso fazê-lo em 2 etapas:
command > /dev/null 2> temp.file
grep 'something' temp.file
mas eu preferiria poder fazer isso sem arquivos temporários. Existem truques inteligentes de tubulação?
command 2| othercommand
. O Bash é tão perfeito que o desenvolvimento terminou em 1982, por isso nunca veremos isso no bash, receio.Respostas:
Primeiro redirecione o stderr para o stdout - o pipe; em seguida, redirecione o stdout para
/dev/null
(sem alterar para onde o stderr está indo):Para obter detalhes sobre o redirecionamento de E / S em toda a sua variedade, consulte o capítulo Redirecionamentos no manual de referência do Bash.
Observe que a sequência de redirecionamentos de E / S é interpretada da esquerda para a direita, mas os pipes são configurados antes que os redirecionamentos de E / S sejam interpretados. Descritores de arquivo como 1 e 2 são referências para abrir descrições de arquivo. A operação
2>&1
faz com que o descritor de arquivo 2 aka stderr se refira à mesma descrição de arquivo aberto que o descritor de arquivo 1 aka stdout se refere atualmente (consultedup2()
eopen()
). A operação>/dev/null
altera o descritor de arquivo 1 para que ele se refira a uma descrição de arquivo aberto/dev/null
, mas isso não altera o fato de que o descritor de arquivo 2 se refere à descrição do arquivo aberto que o descritor de arquivo 1 estava apontando originalmente - a saber, o canal.fonte
command 2> /dev/stdout 1> /dev/null | grep 'something'
/dev/stdout
et al, ou use/dev/fd/N
. Eles serão marginalmente menos eficientes, a menos que o shell os trate como casos especiais; a notação numérica pura não envolve acessar arquivos por nome, mas usar os dispositivos significa uma pesquisa de nome de arquivo. Se você pode medir isso é discutível. Gosto da sucessão da notação numérica - mas a uso há tanto tempo (mais de um quarto de século; ai!) Que não estou qualificado para julgar seus méritos no mundo moderno.2>&1
, que significa 'stderr de conexão para o descritor de arquivo que stdout está atualmente indo'. A segunda operação é 'change stdout, para que vá para/dev/null
', deixando o stderr indo para o stdout original, o pipe. O shell divide primeiro as coisas no símbolo do canal, portanto, o redirecionamento do canal ocorre antes dos redirecionamentos2>&1
ou>/dev/null
, mas é tudo; as outras operações são da esquerda para a direita. (Da direita para a esquerda não iria funcionar.)/dev/null
para o equivalente do Windowsnul
).Ou, para trocar a saída do erro padrão e da saída padrão, use:
Isso cria um novo descritor de arquivo (3) e o atribui ao mesmo local que 1 (saída padrão), depois atribui o fd 1 (saída padrão) ao mesmo local que o fd 2 (erro padrão) e, finalmente, atribui o fd 2 (erro padrão) ) para o mesmo local que fd 3 (saída padrão).
O erro padrão agora está disponível como saída padrão e a saída padrão antiga é preservada no erro padrão. Isso pode ser um exagero, mas espero que dê mais detalhes sobre os descritores de arquivos Bash (há nove disponíveis para cada processo).
fonte
3>&-
para fechar o descritor de reposição que você criou a partir stdoutstderr
e outro que tenha a combinação destderr
estdout
? Em outras palavras, podestderr
ir para dois arquivos diferentes ao mesmo tempo?No Bash, você também pode redirecionar para um subshell usando a substituição de processo :
Para o caso em questão:
fonte
command 2> >(grep 'something' > grep.log)
grep.log contenha o mesmo resultado que o ungrepped.log decommand 2> ungrepped.log
2> >(stderr pipe >&2)
. Caso contrário, a saída do "stderr pipe" passará pelo "stdlog pipe".2> >(...)
, funciona, eu tentei,2>&1 > >(...)
mas não o fezawk -f /new_lines.awk <in-content.txt > out-content.txt 2> >(tee new_lines.log 1>&2 )
Nesse caso, eu também queria ver o que estava saindo como erros no meu console. Mas STDOUT estava indo para o arquivo de saída. Portanto, dentro do sub-shell, você precisa redirecionar esse STDOUT de volta para STDERR dentro dos parênteses. Enquanto isso funciona, a saída STDOUT dotee
comando é encerrada no final doout-content.txt
arquivo. Isso parece inconsistente para mim.2>&1 1> >(dest pipe)
Combinando as melhores respostas, se você:
command 2> >(grep -v something 1>&2)
... todo stdout é preservado como stdout e todo stderr é preservado como stderr, mas você não verá nenhuma linha no stderr que contenha a string "something".
Isso tem a vantagem exclusiva de não reverter ou descartar stdout e stderr, nem esmagá-los juntos, nem usar arquivos temporários.
fonte
command 2> >(grep -v something)
(sem1>&2
) o mesmo?tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2)
deve funcionar.É muito mais fácil visualizar as coisas se você pensar sobre o que realmente está acontecendo com "redirecionamentos" e "pipes". Redirecionamentos e canais no bash fazem uma coisa: modifique para onde os descritores de arquivo de processo 0, 1 e 2 apontam para (consulte / proc / [pid] / fd / *).
Quando um tubo ou "|" Se o operador estiver presente na linha de comando, a primeira coisa a acontecer é que o bash cria um fifo e aponta o FD 1 do comando do lado esquerdo para este fifo e aponta o FD 0 do comando do lado direito para o mesmo fifo.
Em seguida, os operadores de redirecionamento de cada lado são avaliados da esquerda para a direita e as configurações atuais são usadas sempre que ocorre a duplicação do descritor. Isso é importante porque, desde que o tubo foi configurado primeiro, o FD1 (lado esquerdo) e o FD0 (lado direito) já foram alterados do que normalmente poderiam ter sido, e qualquer duplicação destes refletirá esse fato.
Portanto, quando você digita algo como o seguinte:
Aqui está o que acontece, em ordem:
Portanto, toda saída que esse "comando" grava em seu FD 2 (stderr) segue para o canal e é lida por "grep" no outro lado. Toda saída que "comando" grava em seu FD 1 (stdout) chega a / dev / null.
Em vez disso, você executa o seguinte:
Aqui está o que acontece:
Portanto, todos os stdout e stderr do "comando" vão para / dev / null. Nada vai para o canal e, assim, o "grep" será fechado sem exibir nada na tela.
Observe também que os redirecionamentos (descritores de arquivo) podem ser somente leitura (<), somente gravação (>) ou leitura e gravação (<>).
Uma nota final. Se um programa grava algo em FD1 ou FD2, depende inteiramente do programador. As boas práticas de programação determinam que as mensagens de erro devem ir para o FD 2 e a saída normal para o FD 1, mas muitas vezes você encontrará uma programação desleixada que mistura os dois ou ignora a convenção.
fonte
Se você estiver usando o Bash, use:
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
fonte
|&
é igual ao2>&1
que combina stdout e stderr. A pergunta solicitou explicitamente a saída sem stdout.>/dev/null |&
expanda para>/dev/null 2>&1 |
e significa que o stode stdout está vazio para canalizar porque ninguém (# 1 # 2 ambos vinculado ao / dev / null inode) está vinculado ao stode stdout (por exemplols -R /tmp/* >/dev/null 2>&1 | grep i
, dará vazio, masls -R /tmp/* 2>&1 >/dev/null | grep i
permite # 2, que está vinculado ao inode stdout, será canalizado).( echo out; echo err >&2 ) >/dev/null |& grep "."
não dá saída (onde queremos "errar").man bash
diz Se | & é usado ... é 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. Então, primeiro redirecionamos o FD1 do comando para nulo, depois redirecionamos o FD2 do comando para onde o FD1 apontou, ou seja. nulo, então o FD0 do grep não recebe entrada. Consulte stackoverflow.com/a/18342079/69663 para obter uma explicação mais detalhada.Para aqueles que desejam redirecionar stdout e stderr permanentemente para arquivos, grep no stderr, mas mantenha o stdout para escrever mensagens em um tty:
fonte
Isso redirecionará command1 stderr para command2 stdin, deixando o command1 stdout como está.
Retirado do LDP
fonte
Acabei de criar uma solução para enviar
stdout
para um comando estderr
para outro, usando pipes nomeados.Aqui vai.
Provavelmente, é uma boa idéia remover os pipes nomeados posteriormente.
fonte
Você pode usar o shell rc .
Primeiro instale o pacote (tem menos de 1 MB).
Este um exemplo de como você iria descartar saída padrão e tubo de erro padrão para grep em
rc
:Você pode fazer isso sem sair do Bash:
Como você deve ter notado, é possível especificar qual descritor de arquivo você deseja canalizar usando colchetes após o canal.
Os descritores de arquivo padrão são numerados da seguinte forma:
fonte
Eu tento seguir, acho que funciona também,
fonte