Як використовувати sed, щоб маніпулювати вихідним потоком?


13

Я збираю презентацію для нетехнічної аудиторії. У мене є програма, що працює в bash, яка виводить безперервний потік значень, кілька з яких є важливими. Я хотів би виділити важливі результати, оскільки вони відображаються, щоб аудиторія змогла зрозуміти їх частоту. Проблема полягає в тому, що я не можу дістатись sedдо запущеного потоку. Це добре працює, якщо я помістив результати у файл, як у:

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

Але якщо я спробую те ж саме на запущеному виході, як це:

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

sedнічого не робить. Будь-які думки?

Як Ламберт був досить корисним, щоб сказати, моє висловлювання, що sedнічого не робило, було неясним. Що відбувається, це те, що програма виводить stdout(я майже впевнений, що це не пише stderr), як це було б нормально, навіть якщо вона проходить через sed.

Проблема, здається, полягає в тому, що команда викликає другу програму, яка потім виводить у stdout. Є кілька рядків, надрукованих першою програмою; це я можу редагувати. Потім є потік значень, надрукований другою програмою; це я не можу редагувати.

Методи Perl і awk також не працюють.


5
Чи stdbuf -o0 command | sed "s/some text/some text bolded/"працює?
FloHimself

3
"Sed нічого не робить" ви маєте на увазі, що заміна не проводиться, або у вас немає результатів? Можливо, команда пише в stderr замість stdout? Якщо ви хочете виділити щось, що ви можете використовуватиcommand|egrep 'some text|$'
Ламберт

Чи пише команда stdout (а не stderr)?
Антон

1
Зважаючи на те, що текст з’являється не раз, ви повинні додати gотриману "глобальну" заміну, інакше буде замінено лише перше виникнення у рядку:sed "s/old/new/g"
ph0t0nix

@ ph0t0nix Ні, це не проблема, але це була б проблема внизу лінії. Дякую за пораду.
P Jones

Відповіді:


12

Ймовірно, що вихід команди буферизований. Коли команда записує в термінал, буфер видається на кожному новому рядку, тож ви бачите, що він відображається із очікуваною швидкістю. Коли команда записує в трубу, буфер розмивається лише тоді, коли він досягає кількох кілобайт, тому він сильно відстає. Таким чином, поведінка за замовчуванням стандартної бібліотеки вводу / виводу.

Щоб змусити команду не буфетувати її вихід, ви можете використовувати unbuffer(з очікування) або stdbuf(з GNU coreutils).

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

stdbufне працював (про це згадувалося раніше, BTW), але unbufferзробив !! Ви не маєте поняття, наскільки щасливим ви мене зробили.
P Jones

І дякую за стисле пояснення. Дуже корисний.
P Jones

sedсам використовує такий буфер, (див. ChennyStar post), тому приклади тут можуть не працювати, оскільки sedє commandрозпалювачем: cat /etc/passwd | unbuffer sedале sedсам має -uможливість, тому grepможе бути більш підходящим у цих прикладах. Дякую за вашу основну інформацію! Чудова відповідь!
математика

4

sed є варіант для цього:

-у, - незабруднений

Котрий завантажує мінімальну кількість даних із вхідних файлів і частіше вимиває вихідні буфери. Дивіться man sedдокладнішу інформацію.


1
sedЛише GNU (не BSD sed), і я вважаю, що це все-таки не перешкоджатиме буферизації команди на початку труби. Але добре це згадати. :)
Wildcard

На сторінці man-stdbuf вказується, що "Якщо COMMAND налаштовує буферизацію своїх стандартних потоків (наприклад, 'tee' робить), то це замінить відповідні зміни на 'stdbuf'." Схоже, sed може потрапити до цієї категорії, але прапор '-u' зробить його корисним у нерозподіленому ланцюзі труб.
MattSmith

2

Я б використав awk

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

де

  • /some important stuff/ виберіть важливий рядок, як у sed
  • printf "%c[31m%s%c[0m\n",27,$0,27 ; друк червоним кольором
    • використовувати 32,33 для зеленого, жовтого ...
    • $ 1, $ 2 можна використовувати для вибору конкретного поля
  • інший рядок просто надруковано "як є"

Ключовим моментом є те, що commandслід розмивати лінії, але це має бути так, якщо у вас є багато результатів.


Примітка. Питання не говорить про те, що весь рядок повинен бути "жирним", а просто "якийсь текст". Хоча можливо також реалізувати цю функцію в awk(з використанням sub()або gsub()), у випадку цієї примітивної заміни sed, безумовно, є відповідним інструментом.
Яніс

1

Перл-спосіб:

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

або з безперервним виходом:

Баш сценарій для виводу cont:

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

Тест за допомогою:

./cont | perl -pe 's/(stuff)/\x1b[1m${1}\x1b[0m/g'
  • \x1b[1m - сміливу або підвищену інтенсивність
  • ${1} - зворотній довідник
  • \x1b[0m - скидання всіх атрибутів

Вихід:

Деякі речі
Деякі речі
Деякі речі
Деякі речі

Більше кодів евакуації тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.