Estou usando o ffmpeg para obter as informações meta de um clipe de áudio. Mas eu sou incapaz de cumprimentá-lo.
$ ffmpeg -i 01-Daemon.mp3 |grep -i Duration
FFmpeg version SVN-r15261, Copyright (c) 2000-2008 Fabrice Bellard, et al.
configuration: --prefix=/usr --bindir=/usr/bin
--datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib
--mandir=/usr/share/man --arch=i386 --extra-cflags=-O2
...
Eu verifiquei, essa saída ffmpeg é direcionada para stderr.
$ ffmpeg -i 01-Daemon.mp3 2> /dev/null
Então, acho que o grep não consegue ler o fluxo de erro para pegar as linhas correspondentes. Como podemos habilitar o grep para ler o fluxo de erros?
Usando o link nixCraft , redirecionei o fluxo de erro padrão para o fluxo de saída padrão e o grep funcionou.
$ ffmpeg -i 01-Daemon.mp3 2>&1 | grep -i Duration
Duration: 01:15:12.33, start: 0.000000, bitrate: 64 kb/s
Mas e se não quisermos redirecionar o stderr para o stdout?
grep
io-redirection
ffmpeg
Andrew-Dufresne
fonte
fonte
grep
só possa operar no stdout (embora não seja possível encontrar a fonte canônica para fazer o backup), o que significa que qualquer fluxo precisa ser convertido para o stdout primeiro.grep
só pode operar em stdin. É o pipe criado pelo shell que conecta o stdin do grep ao stdout do outro comando. E o shell pode conectar apenas um stdout a um stdin.Respostas:
Se você está usando,
bash
por que não empregar tubos anônimos, em essência, uma abreviação do que phunehehe disse:ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)
fonte
cp
saídacp -r dir* to 2> >(grep -v "svn")
>&2
, por exemplo,command 2> >(grep something >&2)
2>
redireciona stderr para arquivo, eu entendo isso. Isso lê do arquivo>(grep -i Duration)
. Mas o arquivo nunca é armazenado? Como é chamada essa técnica para que eu possa ler mais sobre ela?Nenhuma das conchas usuais (mesmo o zsh) permite outros canais além de stdout para stdin. Mas todas as conchas no estilo Bourne suportam a reatribuição de descritor de arquivo (como em
1>&2
). Assim, você pode desviar temporariamente o stdout para o fd 3 e o stderr para o stdout, e depois colocar o fd 3 novamente no stdout. Sestuff
produz alguma saída no stdout e outra no stderr, e você deseja aplicarfilter
na saída de erro deixando a saída padrão intacta, você pode usá-lo{ stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
.fonte
pipestatus
ajudariaset -o pipefail
pode ser útil aqui, dependendo do que você deseja fazer com o status do erro. (Por exemplo, se tiverset -e
ligado a falhar em algum erro, você provavelmente vai quererset -o pipefail
também.)set -e
a falha em qualquer erro.rc
carcaça permite a tubulação stderr. Veja minha resposta abaixo.Isso é semelhante ao "truque de arquivo temporário" do phunehehe, mas usa um pipe nomeado, permitindo obter resultados um pouco mais próximos da saída, o que pode ser útil para comandos de longa execução:
Nesta construção, o stderr será direcionado para o tubo chamado "mypipe". Como
grep
foi chamado com um argumento de arquivo, ele não procurará STDIN por sua entrada. Infelizmente, você ainda precisará limpar esse pipe nomeado quando terminar.Se você estiver usando o Bash 4, há uma sintaxe de atalho para
command1 2>&1 | command2
, que écommand1 |& command2
. No entanto, acredito que este é apenas um atalho de sintaxe, você ainda está redirecionando STDERR para STDOUT.fonte
|&
sintaxe é perfeita para limpar os traços de pilha inchados do Ruby stderr. Finalmente posso cumprimentar aqueles sem muito trabalho.As respostas de Gilles e Stefan Lasiewski são boas, mas dessa maneira é mais simples:
Suponho que você não queira
ffmpeg's
imprimir stdout.Como funciona:
fonte
Veja abaixo o script usado nesses testes.
O Grep pode operar apenas em stdin, portanto, você deve converter o fluxo stderr em um formato que o Grep possa analisar.
Normalmente, stdout e stderr são impressos na sua tela:
Para ocultar o stdout, mas ainda assim imprimir stderr, faça o seguinte:
Mas o grep não funcionará no stderr! Você esperaria que o seguinte comando suprimisse as linhas que contêm 'err', mas não contém.
Aqui está a solução.
A seguinte sintaxe do Bash oculta a saída para stdout, mas ainda mostra o stderr. Primeiro canalizamos o stdout para / dev / null, depois convertemos o stderr para o stdout, porque os pipes do Unix operam apenas no stdout. Você ainda pode grep o texto.
(Note-se que o comando acima é diferente , em seguida
./command >/dev/null 2>&1
, o que é um comando muito comum).Aqui está o script usado para o teste. Isso imprime uma linha para stdout e uma linha para stderr:
fonte
./stdout-stderr.sh 2>&1 >/dev/null | grep err
.Ao canalizar a saída de um comando para outro (usando
|
), você está redirecionando apenas a saída padrão. Então, isso deve explicar o porquênão gera o que você queria (mas funciona).
Se você não deseja redirecionar a saída de erro para a saída padrão, pode redirecionar a saída de erro para um arquivo e depois cumpri-lo
fonte
it does work, though
, você quer dizer que está funcionando na sua máquina? Em segundo lugar, como você apontou usando o pipe, só podemos redirecionar o stdout. Estou interessado em algum recurso de comando ou bash que me permitirá redirecionar o stderr. (mas não o truque arquivo temporário)Você pode trocar os fluxos. Isso permitiria
grep
o fluxo de erros padrão original enquanto ainda obtivemos a saída que foi originalmente para a saída padrão no terminal:Isso funciona criando primeiro um novo descritor de arquivo (3) aberto para saída e configurando-o para o fluxo de erro padrão (
3>&2
). Em seguida, redirecionamos o erro padrão para a saída padrão (2>&1
). Finalmente, a saída padrão é redirecionada para o erro padrão original e o novo descritor de arquivo é fechado (1>&3-
).No seu caso:
Testando:
fonte
Eu gosto de usar o
rc
shell neste caso.Primeiro instale o pacote (é inferior a 1 MB).
Este é um exemplo de como você descartaria
stdout
e canalizariastderr
para greprc
:find /proc/ >[1] /dev/null |[2] grep task
Você pode fazer isso sem sair do Bash:
rc -c 'find /proc/ >[1] /dev/null |[2] grep task'
Como você deve ter notado, a sintaxe é direta, o que torna essa a minha solução preferida.
Você pode especificar qual descritor de arquivo você deseja canalizar entre colchetes, logo após o caractere de barra vertical.
Os descritores de arquivo padrão são numerados da seguinte forma:
fonte
Uma variação no exemplo do subprocesso do bash:
eco duas linhas para stderr e tee stderr para um arquivo, grep o tee e canalize de volta para stdout
stdout:
some.load.errors (por exemplo, stderr):
fonte
tente este comando
ceva -> apenas um nome de variável (english = something)
fonte
/tmp/$ceva
, melhor do que desarrumar o diretório atual com arquivos temporários - e você está assumindo que o diretório atual é gravável.