Як "перехопити" безперервний потік?


729

Чи можливо це використовувати grepв безперервному потоці?

Що я маю на увазі, це свого роду tail -f <file>команда, але з grepвиведенням, щоб зберегти лише ті рядки, які мене цікавлять.

Я намагався, tail -f <file> | grep patternале здається, що grepйого можна виконати лише один раз, коли tailзакінчується, тобто ніколи.


9
З великою ймовірністю програма, що генерує файл, не видає свій вихід.
Стів-о

tail -f fileтвори (я бачу новий вихід у режимі реального часу)
Матьє Наполі

6
Було б доречно на unix.stackexchange.com
Люк М

@Luc дійсно, не думав про це
Матьє Наполі

Можливо, у потоці введення немає нових рядків? Якщо так, греп не буде продовжуватися.
Лінч

Відповіді:


1326

Увімкніть grepрежим буферизації лінії при використанні BSD grep (FreeBSD, Mac OS X тощо)

tail -f file | grep --line-buffered my_pattern

Вам не потрібно робити це для GNU grep (використовується майже на будь-якому Linux), оскільки воно за замовчуванням змине (YMMV для інших подібних Unix, таких як SmartOS, AIX або QNX).


3
@MichaelNiemand ви можете використовувати хвостовий -F файл | grep
line

47
@MichaelGoldshteyn Склади це легко. Люди підкреслюють це, тому що вони знаходять цю сторінку, коли вони перебувають у Google "grep line buffered", і це вирішує для них проблему, яка не може бути точно тією, яка постає як питання.
дощ

4
Я приїхав сюди, намагаючись збагнути вихід strace. Без цього --line-bufferedне вийде.
sjas

5
@MichaelGoldshteyn (і прихильники його коментаря): Я завжди мав цю проблему tail -f | grepі --line-bufferedвирішує її для мене (на Ubuntu 14.04, GNU grep версія 2.16). Де реалізована логіка "використання буферизації рядків, якщо stdout - це tty"? У git.savannah.gnu.org/cgit/grep.git/tree/src/grep.c , line_bufferedвстановлюється тільки з допомогою аргументу синтаксичного аналізу.
Аасмунд Елдхусет

8
@MichaelGoldshteyn Я на macOS, використовуючи BSD grep, і без --line-bufferedмене не виходить вихід. Однак після тестування схоже, що GNU grep робить те, що ви описуєте. Так, як і більшість речей Unix, це залежить від реалізації вашої платформи. Оскільки питання не визначає платформу, ваша інформація видається помилковою - після перегляду коду BSD grep та порівняння його з GNU grep, поведінка, безумовно, контролюється опцією - buffe-buffere. Просто за замовчуванням промиває лише GNU grep.
Річард Уейт

118

Я tail -f <file> | grep <pattern>весь час використовую.

Він зачекатиме, поки греп не змине, а не поки не закінчиться (я використовую Ubuntu).


4
Що може тривати досить довго, тому намагайтеся не ставати нетерплячим.
glglgl

Скільки часу може пройти приблизно?
Матьє Наполі

@Matthieu: Залежить в основному від того, на що ти схопишся, і від того, наскільки великі буфери у вашій ОС. Якщо греп збігається лише на коротку струну кожні кілька годин, це пройде за кілька днів до першого флешу.
tripleee

13
Хвост не використовує буферизацію виводу - grep робить.
XzKto

7
Ні, grep не робить буферизацію виходу, коли вихід збирається на tty-пристрій, як це явно є у цій відповіді. Це робить буферизацію ліній! Це правильна відповідь і повинна бути прийнятою відповіддю. Дивіться мій довший коментар до прийнятої ( неправильної ) відповіді для отримання більш детальної інформації.
Майкл Голдштейн

67

Я думаю, що ваша проблема полягає в тому, що grep використовує деяку вихідну буферизацію. Спробуйте

tail -f file | stdbuf -o0 grep my_pattern

він встановить вихідний режим буферизації grep на небуферизований.


7
І це має ту перевагу, що він може бути використаний для багатьох інших команд grep.
Петро В. Морч

4
Однак, як я виявив після того, як більше граю з ним, деякі команди лише вимикають свої дані, коли вони підключені до tty, і для цього unbufferexpect-devпакеті на debian) є king . Тому я використовував би unbuffer через stdbuf.
Пітер В. Морч

5
@Peter V. Mørch Так, ти маєш рацію, unbuffer іноді може працювати там, де stdbuf не може. Але я думаю, ви намагаєтесь знайти «магічну» програму, яка завжди вирішить ваші проблеми замість того, щоб зрозуміти вашу проблему. Створення віртуального tty - не пов'язане завдання. Stdbuf робить саме те, що ми хочемо (встановлює стандартний вихідний буфер, щоб надати значення), тоді як unbuffer робить багато прихованих речей, які ми можемо не хотіти (порівняйте інтерактивні topз stdbuf та unbuffer). І насправді немає жодного "магічного" рішення: unbuffer іноді також виходить з ладу, наприклад, awk використовує різну реалізацію буфера (stdbuf також вийде з ладу).
XzKto

2
"Але я думаю, що ви намагаєтесь знайти" магічну "програму, яка завжди виправить ваші проблеми, а не зрозуміти вашу проблему". - Я думаю, ти маєш рацію! ;-)
Петро В. Морч

1
Ще детальну інформацію про stdbuf, "unbuffer and stdio buffering" на pixelbeat.org/programming/stdio_buffering
Tor

13

Якщо ви хочете знайти збіги у всьому файлі (а не лише в хвостику), і ви хочете, щоб він сидів і чекав будь-яких нових збігів, це добре працює:

tail -c +0 -f <file> | grep --line-buffered <pattern>

-c +0Прапор говорить про те , що вихід повинен починатися 0байт ( -c) з самого початку ( +) файлу.


12

У більшості випадків ви можете, tail -f /var/log/some.log |grep fooі це спрацює просто чудово.

Якщо вам потрібно скористатися декількома грейпами для запущеного файлу журналу, і ви виявите, що у вас немає виводу, можливо, вам доведеться вставити --line-bufferedперемикач у свій середні грепи, наприклад:

tail -f /var/log/some.log | grep --line-buffered foo | grep bar

7

Ви можете розглянути цю відповідь як вдосконалення .. зазвичай я використовую

tail -F <fileName> | grep --line-buffered  <pattern> -A 3 -B 5

-F краще в разі обертання файлу (-f не працюватиме належним чином, якщо файл обертається)

-A і -B корисно отримувати рядки безпосередньо до і після появи шаблону .. ці блоки з’являться між штриховими роздільниками рядків

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

tail -F <file> | less

це дуже корисно, якщо ви хочете шукати все потокові журнали. Я маю на увазі повернутися назад і вперед і глибоко дивитися


4
grep -C 3 <pattern>, замінює -A <N> і -B <N>, якщо N однаково.
AKS

6

Я не бачив, щоб хтось пропонував моє звичайне звернення для цього:

less +F <file>
ctrl + c
/<search term>
<enter>
shift + f

Я вважаю за краще це, тому що ви можете використовувати ctrl + cдля зупинки та навігації по файлу коли завгодно, а потім просто натисніть, shift + fщоб повернутися до прямого потокового пошуку.


4

sed буде кращим вибором ( редактор потоку )

tail -n0 -f <file> | sed -n '/search string/p'

а потім, якщо ви хочете, щоб команда хвоста завершилася, як тільки ви знайшли певну рядок:

tail --pid=$(($BASHPID+1)) -n0 -f <file> | sed -n '/search string/{p; q}'

Очевидно, що башизм: $ BASHPID буде ідентифікатором процесу хвостової команди. Команда sed є наступною за хвостом у трубі, тож id процесу обробки буде $ BASHPID + 1.


1
Припущення про те, що наступний процес, розпочатий у системі ( $BASHPID+1), буде вашим, є помилковим у багатьох ситуаціях, і це не робить нічого для вирішення проблеми буферизації, яка, ймовірно, намагалася задати ОП. Зокрема, рекомендуючи sedбільше grepтут , здається , як тільки питання (сумнівного) переваги. (Ви можете p;qgrep -m 1
проявити

Працює, команда sed друкує кожний рядок, як тільки вони будуть готові, команда grep з --line-bufferedне зробила. Я щиро не розумію мінус 1.
МУЙ Бельгія

Наразі встановлено, що буферизація є проблемою із грепом . Ніяких спеціальних дій не потрібно обробляти буферизацією ліній за допомогою sed , це поведінка за замовчуванням, звідси мій акцент у потоці слів . І правда, немає гарантії $ BASHPID + -будет правильний PID слідувати, але оскільки PID розподіл є послідовним і конвеєрної команда присвоюється PID відразу ж після, це абсолютно ймовірно.
Крістіан Герр

1

Так, це насправді буде добре. Grepі більшість команд Unix працюють на потоках по одному рядку. Кожен рядок, який виходить із хвоста, буде проаналізований та переданий, якщо він відповідає.


2
Це насправді не правильно. Якщо grepостання команда в ланцюзі труб, вона буде діяти, як ви пояснюєте. Однак, якщо він знаходиться в середині, він одночасно буферизує близько 8k виводу.
Махмуд Аль-Кудсі

1

Ця команда працює для мене (Suse):

mail-srv:/var/log # tail -f /var/log/mail.info |grep --line-buffered LOGIN  >> logins_to_mail

збір входів на поштову службу


-1

вам точно не вдасться

tail -f /var/log/foo.log |grep --line-buffered string2search

коли ви використовуєте "colortail" як псевдонім для хвоста, наприклад. в баш

alias tail='colortail -n 30'

Ви можете перевірити псевдонім, якщо він видає щось на зразок псевдоніма хвоста colortail -n 30 . то ви маєте свого винуватця :)

Рішення:

видалити псевдонім за допомогою

unalias tail

переконайтеся, що ви використовуєте "справжній" двійковий код хвоста за допомогою цієї команди

type tail

який повинен вивести щось на кшталт:

tail is /usr/bin/tail

і тоді ви можете запустити свою команду

tail -f foo.log |grep --line-buffered something

Удачі.


-4

Використовуйте awk (іншу велику утиліту bash) замість grep там, де у вас немає варіанту буферизації ліній! Він буде постійно передавати ваші дані з хвоста.

ось як ви використовуєте grep

tail -f <file> | grep pattern

Ось як би ви використовували awk

tail -f <file> | awk '/pattern/{print $0}'

6
Це неправильно; Awk out of box виконує буферизацію ліній, як і більшість інших стандартних інструментів Unix. (Більше того, {print $0}це зайве, оскільки друк - це дія за замовчуванням, коли умова проходить.)
tripleee
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.