Comment utiliser sed pour manipuler en continu la sortie en streaming?

Je prépare une présentation pour un public non technique. J'ai un programme en bash qui produit un stream continu de valeurs, dont quelques-unes sont importantes. Je voudrais souligner les résultats importants tels qu'ils sont affichés afin que le public puisse avoir une idée de leur fréquence. Le problème est que je ne peux pas get sed pour fonctionner sur un stream en cours d'exécution. Cela fonctionne bien si je mets les résultats dans un file, comme dans:

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

Mais si j'essaie la même chose sur la sortie courante, comme ceci:

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

sed ne fait rien. Des pensées?

Comme Lambert était assez utile pour le souligner, mon affirmation que sed ne faisait rien n'était vague. Ce qui se passe est que le programme sort vers stdout (je suis quasiment sûr que ce n'est pas écrit sur stderr ) comme il le ferait normalement, même s'il est passé par sed .

Le problème semble être que la command appelle un deuxième programme, qui sort ensuite à stdout. Il y a quelques lignes imprimées par le premier programme; ceux-ci je peux éditer. Ensuite, il y a un stream de valeurs imprimées par le deuxième programme; ceux-ci je ne peux pas éditer.

Les methods Perl et awk ne fonctionnent pas non plus.

Les chances sont que la sortie de la command est tamponnée. Lorsque la command écrit sur un terminal, le tampon est vidé sur chaque nouvelle ligne, de sorte que vous voyez qu'il apparaît au taux attendu. Lorsque la command écrit dans un tube, le tampon est seulement vidé lorsqu'il atteint quelques kilo-octets, donc il est très lent. C'est le comportement par défaut de la bibliothèque d'inputs / sorties standard.

Pour forcer la command à ne pas surcharger sa sortie, vous pouvez utiliser unbuffer (à partir de expect) ou stdbuf (à partir de GNU coreutils).

 unbuffer command | sed … stdbuf -o0 command | sed … 

J'utiliserais awk

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

  • /some important stuff/ select une ligne importante, comme dans sed
  • printf "%c[31m%s%c[0m\n",27,$0,27 ; imprimer en rouge
    • utiliser 32,33 pour le vert, le jaune …
    • $ 1, $ 2, peut être utilisé pour sélectionner un champ spécifique
  • autre ligne sont juste imprimés 'en l'état'

le point key est que la command devrait rincer les lignes, mais cela devrait être le cas si vous avez beaucoup de sortie.

La manière perl:

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

ou avec une sortie continue:

Un script bash pour la sortie cont :

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

Testez avec:

 ./cont | perl -pe 's/(stuff)/\x1b[1m${1}\x1b[0m/g' 
  • \x1b[1m – audace ou intensité accrue
  • ${1} – le backreferenze
  • \x1b[0m – réinitialise tous les attributes

Sortie:

Quelques trucs
Quelques trucs
Quelques trucs
Quelques trucs

Plus de codes d'échappement ici .

sed a une option pour cela:

-u, –unbuffered

Ce qui charge des quantités minimes de données à partir des files d'input et vire les tampons de sortie plus souvent. Voir man sed pour plus de détails.