Como usar o sed para manipular continuamente a saída de streaming?

12

Estou organizando uma apresentação para um público não técnico. Eu tenho um programa em execução no bash que gera um fluxo contínuo de valores, alguns dos quais são importantes. Gostaria de destacar os resultados importantes à medida que eles são exibidos para que o público possa ter uma ideia de sua frequência. O problema é que não consigo fazer com que sed funcione em um fluxo em execução. Funciona bem se eu colocar os resultados em um arquivo, como em:

cat output.txt | sed "s/some text/some text bolded/"

Mas se eu tentar a mesma coisa na saída em execução, assim:

command | sed "s/some text/some text bolded/"

sed não faz nada. Alguma ideia?

Como Lambert foi útil o suficiente para apontar, meu dizer que sed não faz nada foi vago. O que está acontecendo é que o programa retorna para stdout (eu tenho certeza que não está escrevendo para stderr ) como normalmente faria, mesmo que seja canalizado através de sed .

O problema parece ser que o comando chama um segundo programa, que então é enviado para o stdout. Existem algumas linhas impressas pelo primeiro programa; esses eu posso editar. Depois, há um fluxo de valores impressos pelo segundo programa; estes eu não posso editar.

Os métodos Perl e awk também não funcionam.

    
por P Jones 04.05.2015 / 09:17

4 respostas

10

Provavelmente, a saída do comando está em buffer. Quando o comando grava em um terminal, o buffer é liberado em cada nova linha, para que você veja a taxa esperada. Quando o comando grava em um pipe, o buffer é liberado apenas quando atinge alguns kilobytes, portanto, ele fica muito lento. Assim é o comportamento padrão da biblioteca padrão de entrada / saída.

Para forçar o comando a não fazer o buffet de sua saída, você pode usar unbuffer (do esperado) ou stdbuf (do GNU coreutils).

unbuffer command | sed …
stdbuf -o0 command | sed …
    
por 05.05.2015 / 00:40
2

Eu usaria o awk

  command | awk '/some important stuff/ { printf "%c[31m%s%c[0m\n",27,$0,27 ; next }
  { print ; } '

onde

  • /some important stuff/ seleciona uma linha importante, como em sed
  • printf "%c[31m%s%c[0m\n",27,$0,27 ; imprimir em vermelho
    • use 32,33 para verde, amarelo ...
    • $ 1, $ 2, pode ser usado para selecionar um campo específico
  • outras linhas são impressas 'como estão'

o ponto chave é que command deve liberar as linhas, mas esse deve ser o caso se você tiver muito resultado.

    
por 04.05.2015 / 09:54
2

sed tem uma opção para isso:

-u, --unbuffered

Que carrega quantidades mínimas de dados dos arquivos de entrada e libera os buffers de saída com mais freqüência. Veja man sed para mais detalhes.

    
por 20.01.2016 / 18:30
1

O caminho certo:

command | perl -pe 's/(stuff)/\x1b[1m$1\x1b[0m/g'

ou com uma saída contínua:

Um script bash para a saída cont :

#!/bin/bash
while [ true ]
do
   echo "Some stuff"
done

Teste com:

./cont | perl -pe 's/(stuff)/\x1b[1m${1}\x1b[0m/g'
  • \x1b[1m - negrito ou intensidade aumentada
  • ${1} - o backreferenze
  • \x1b[0m - redefinir todos os atributos

Saída:

Some stuff
Some stuff
Some stuff
Some stuff

Mais códigos de escape aqui .

    
por 04.05.2015 / 10:32