
Estou usando uma ferramenta ( openocd
) que imprime muito lixo, depois uma barra de progresso básica imprimindo lentamente pontos simples e, novamente, algum lixo.
Eu gostaria de filtrar esta saída para grep
que apenas a linha com a barra de progresso seja mostrada e em tempo real (ou seja, cada ponto gerado por openocd
é imediatamente impresso no terminal):
openocd <args> |& grep '^\.'
O problema é que grep
a linha é armazenada em buffer (na melhor das hipóteses), então a barra de progresso não será mostrada até que seja concluída.
Como posso fazer isso grep
ou existe alguma alternativa padrão para conseguir isso? Se houver uma maneira de passar pela openocd
configuração, isso seria útil, embora eu prefira uma solução mais geral.
Responder1
Este é um tipo de resposta hacky/incomum, o fato é que isso provavelmente é possível de uma forma não muito limpa.
grep
em si parece imprimir apenas a saída quando encontra um caractere de nova linha, sua barra de progresso provavelmente não introduz um caractere de nova linha quando é atualizada, daí o seu problema.
strace
é uma ferramenta usada para visualizar as chamadas do sistema que um comando está chamando, isso inclui coisas como ler e gravar coisas na memória/armazenamento, bem como abrir/fechar descritores de arquivo.
Com strace
você pode ver o que um processo está acessando, no caso do seu pipe stout
estar sendo passado para grep
, então strace
você pode ver o texto que está sendo alimentado para grep
. strace
receberá regularmente a saída proveniente do comando canalizado, e você poderá detectar essa saída e exibi-la. Eu estava testando com rsync --progress
, o que parece ocorrer em um cenário semelhante. Usei grep
no ##%
porque é isso que rsync
mostra o progresso.
rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%"
Se você executar este comando, descobrirá que strace
não tem uma boa saída, mas quando o usei, strace
capturou alguns read
s do rsync
que grep
normalmente não aconteceria write
, mostrando read
s para 0%, 21%, 45%, 68%, 91% e 100% pareciam atualizar a cada segundo (provavelmente com base na frequência rsync
de atualização do progresso).
Então com isso você consegue grep
a strace
saída, o que não é muito legal, chamando a mesma grep
novamente.
rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%" 2>&1 > /dev/null | grep -o "[0-9]*%"
O 2>&1
é importante porque strace
imprime em stderr
. Os > /dev/null
redirecionamentos stdout
para /dev/null
evitar que a saída do primeiro grep
seja relatada. O resultado final disso foi a seguinte saída:
0%
21%
45%
68%
91%
100%
Você terá que trocar o grep
, mas parece que isso resolverá o problema. Não é bonito, mas funciona e contorna as restrições do grep
. Parece que grep -f
funciona como tail -f
seria útil (eu sei grep -f
que já está em uso).
A primeira grep
é principalmente apenas para filtrar o texto que strace
será read
enviado, já que apenas as linhas correspondentes serão listadas nas chamadas strace
s read
, mas você também precisa de algo para o texto se mover para strace
poder assisti-lo.
Responder2
Estou gastando na resposta do Centimane porque a resposta final é bastante complicada.
Já era bastante hackeado... agora se torna realmente péssimo:
make flash \
|& strace -e trace=read grep -e "^\." -e rror \
|& stdbuf -o0 sed -ne 's/^.*"\.".*/\./p;/rror/p' \
| stdbuf -o0 tr -d '\n' \
; echo
Portanto, o make flash
acima está chamando openocd
;
strace
está usando o hack do Centimane explicado acima;
sed
substitua read(0, ".", xxx)
linhas por single .
;
tr
está mantendo tudo .
em uma linha e o eco final está colocando o único EOL.
Além disso, sed
e tr
são chamados com stdbuf -o0
o qual define o tamanho do buffer stdout como 0 (porque o EOL foi removido) e grep/sed
também combinam (e)rror
para imprimir algum lixo em caso de erro.
Tentei fatorar todo esse inchaço ao mínimo, mas não consegui fazer melhor.
Observe também que estou usando o zsh/Ubuntu 14.04 e não tenho certeza se isso pode funcionar em outro Unix.