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

4

Estou usando uma ferramenta ( openocd ) que imprime muito lixo, depois uma barra de progresso básica imprimindo lentamente pontos simples e, em seguida, novamente um pouco de lixo.

Eu gostaria de filtrar essa saída com grep , então somente a linha com barra de progresso é mostrada, e em tempo real (ou seja, cada ponto gerado por openocd é imediatamente impresso no terminal):

openocd <args> |& grep '^\.'

O problema é que grep é armazenado em buffer de linha (na melhor das hipóteses), portanto, a barra de progresso não será mostrada até que seja concluída.

Como posso fazer com grep ou existe alguma alternativa padrão para isso? Se houver um caminho na configuração de openocd , isso seria útil, embora eu preferisse uma solução mais geral.

    
por calandoa 15.12.2016 / 16:08

2 respostas

3

Este é um tipo de resposta hacky / incomum, o fato é que isso é provavelmente possível de uma forma não muito limpa.

grep parece apenas imprimir a saída quando encontra um caractere de nova linha, sua barra de progresso provavelmente não introduz um caractere de nova linha quando é atualizado, 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 escrever coisas na memória / armazenamento, bem como abrir / fechar descritores de arquivos.

Com strace você pode ver o que um processo está acessando, no caso de seu canal stout ser passado para grep , então com strace você pode ver o texto sendo alimentado para grep . strace será regularmente enviado a saída proveniente do comando canalizado, e você pode cheirar essa saída e exibi-lo. Eu estava testando com rsync --progress , o que parece ter um cenário semelhante. Eu usei grep no ##% porque é isso que o rsync usa para mostrar o progresso.

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

Se você executar esse comando, verá que strace não tem resultados bons, mas que quando eu usei, strace capturou alguns read s do rsync que grep normalmente write , mostrando read s para 0%, 21%, 45%, 68%, 91% e 100%, parecia atualizar sobre cada segundo (provavelmente com base na frequência com que rsync atualiza o progresso).

Então, com isso você pode grep a strace output, o que não é muito bom, chamando o mesmo 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 é impresso em stderr . O > /dev/null redireciona stdout para /dev/null para evitar que a saída do primeiro grep seja reportada. O resultado final disso foi a seguinte saída:

0%
21%
45%
68%
91%
100%

Você terá que trocar o grep , mas parece que vai dar certo. Não é bonito, mas funciona e trabalha em torno das restrições de grep . Parece que um grep -f que funciona como tail -f seria útil (eu sei que grep -f já está em uso).

O primeiro grep é principalmente apenas para filtrar o texto que strace será read ing, pois somente as linhas correspondentes serão listadas em strace s read chamadas, mas você também precisa de algo para o texto estar se movendo através de strace pode assisti-lo.

    
por 15.12.2016 / 21:46
2

Estou gastando com a resposta do Centimane, pois a resposta final é bem complicada.

Já era bem hacky ... agora fica muito ruim:

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 de Centimane explicado acima;

sed replace read(0, ".", xxx) linhas por único . ;

tr está mantendo todos os . em uma linha e o eco final está colocando a única EOL.

Além disso, sed e tr são chamados com stdbuf -o0 , que define o tamanho do buffer stdout como 0 (porque o EOL foi removido) e grep/sed também estão combinando (e)rror para imprimir algum lixo no caso de erro.

Eu tentei fatorar todo esse inchaço ao mínimo, mas não consegui fazer melhor.

Note também que estou usando o zsh / Ubuntu 14.04, e não tenho certeza se isso pode funcionar em outro Unix.

    
por 16.12.2016 / 14:31