Como fazer grep em tempo real em uma saída contendo uma barra de progresso?

Como fazer grep em tempo real em uma saída contendo uma barra de progresso?

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 grepque 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 grepa 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 grepou existe alguma alternativa padrão para conseguir isso? Se houver uma maneira de passar pela openocdconfiguraçã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.


grepem 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 stracevocê pode ver o que um processo está acessando, no caso do seu pipe stoutestar sendo passado para grep, então stracevocê pode ver o texto que está sendo alimentado para grep. stracereceberá 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 grepno ##%porque é isso que rsyncmostra o progresso.

rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%"

Se você executar este comando, descobrirá que stracenão tem uma boa saída, mas quando o usei, stracecapturou alguns reads do rsyncque grepnormalmente não aconteceria write, mostrando reads para 0%, 21%, 45%, 68%, 91% e 100% pareciam atualizar a cada segundo (provavelmente com base na frequência rsyncde atualização do progresso).

Então com isso você consegue grepa stracesaída, o que não é muito legal, chamando a mesma grepnovamente.

rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%" 2>&1 > /dev/null | grep -o "[0-9]*%"

O 2>&1é importante porque straceimprime em stderr. Os > /dev/nullredirecionamentos stdoutpara /dev/nullevitar que a saída do primeiro grepseja 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 -ffunciona como tail -fseria útil (eu sei grep -fque já está em uso).

A primeira grepé principalmente apenas para filtrar o texto que straceserá readenviado, já que apenas as linhas correspondentes serão listadas nas chamadas straces read, mas você também precisa de algo para o texto se mover para stracepoder 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 flashacima está chamando openocd;

straceestá usando o hack do Centimane explicado acima;

sedsubstitua read(0, ".", xxx)linhas por single .;

trestá mantendo tudo .em uma linha e o eco final está colocando o único EOL.

Além disso, sede trsão chamados com stdbuf -o0o qual define o tamanho do buffer stdout como 0 (porque o EOL foi removido) e grep/sedtambém combinam (e)rrorpara 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.

informação relacionada