Как «grep» непрерывный поток?

638

Можно ли использовать grep для непрерывного потока?

Я имею в виду некоторую команду tail -f <file>, но с grep на выходе, чтобы сохранить только интересующие меня строки.

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

  • 9
    Весьма вероятно, что программа, генерирующая файл, не сбрасывает вывод.
  • 0
    работает tail -f file (я вижу новый вывод в реальном времени)
Показать ещё 7 комментариев
Теги:
grep
tail

11 ответов

1184
Лучший ответ

Включите режим буферизации строки grep при использовании BSD grep (FreeBSD, Mac OS X и т.д.)

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

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

  • 2
    что произойдет, если я подключу файл журнала, который будет вращаться, пока он работает? Будет ли logrotate иметь возможность вращать файл?
  • 3
    @MichaelNiemand и вы можете использовать tail -F file | grep - line-buffered my_pattern
Показать ещё 8 комментариев
108

Я использую tail -f <file> | grep <pattern> все время.

Он будет ждать, пока grep не начнет сбрасываться, пока он не закончится (я использую Ubuntu).

  • 3
    Что может длиться довольно долго, поэтому постарайтесь не терять терпение.
  • 0
    Сколько времени это может занять примерно?
Показать ещё 5 комментариев
53

Я думаю, что ваша проблема в том, что grep использует некоторую буферизацию вывода. Попробуйте

tail -f file | stdbuf -o0 grep my_pattern

он установит режим буферизации вывода grep небуферизованным.

  • 7
    И это имеет то преимущество, что может использоваться для многих других команд, кроме grep .
  • 4
    Однако, как я обнаружил после более подробного изучения, некоторые команды сбрасывают свой вывод только при подключении к tty, и для этого unbuffer (в пакете expect-dev на debian) является королем . Так что я бы использовал unbuffer поверх stdbuf.
Показать ещё 3 комментария
8

В большинстве случаев вы можете tail -f /var/log/some.log |grep foo, и он будет работать нормально.

Если вам нужно использовать несколько grep в работающем файле журнала, и вы обнаружите, что у вас нет выхода, вам может понадобиться вставить переключатель --line-buffered в grep (s) средний, например так:

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

Если вы хотите найти совпадения во всем файле (а не только в хвосте), и вы хотите, чтобы он сидел и ждал новых совпадений, это прекрасно работает:

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

Флаг -c +0 указывает, что выход должен начинаться с 0 bytes (-c) с начала (+) файла.

3

Не видел, чтобы кто-нибудь предложил мое обычное решение для этого:

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

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

1

sed будет лучшим выбором (редактор потоков)

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

и затем, если вы хотите, чтобы команда tail выходила, как только вы нашли конкретную строку:

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

Очевидно, что bashism: $ BASHPID будет идентификатором процесса команды tail. Команда sed будет следующей после tail в конвейере, поэтому идентификатор процесса sed будет $ BASHPID + 1.

  • 1
    Предположение о том, что следующий процесс, запущенный в системе ( $BASHPID+1 ), будет вашим, во многих ситуациях ложно, и это ничего не делает для решения проблемы буферизации, о которой, вероятно, пытался спросить OP. В частности, рекомендация sed grep здесь кажется просто вопросом (сомнительного) предпочтения. (Вы можете получить поведение p;q с помощью grep -m 1 если вы пытаетесь достичь этого.)
  • 0
    Работает, команда sed печатает каждую строку, как только она готова, команда grep с параметром --line-buffered нет. Я искренне не понимаю минус 1.
Показать ещё 1 комментарий
1

вы можете рассмотреть этот ответ как улучшение. Обычно я использую

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

-F лучше в случае поворота файла (-f не будет работать должным образом, если файл повернут)

-A и -B полезно для получения строк непосредственно перед и после появления шаблона.. эти блоки появятся между разделителями пунктирных линий

  • 2
    grep -C 3 <pattern> , заменяет -A <N> и -B <N>, если N одинаково.
0

Эта команда работает для меня (Suse):

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

сбор логинов к почтовому сервису

0

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

  • 2
    Это не совсем правильно. Если grep является последней командой в цепочке каналов, она будет действовать так, как вы объясните. Однако, если он находится посередине, он будет буферизовать около 8 тыс. Выводов одновременно.
-2

Используйте awk (еще одна полезная утилита bash) вместо grep, где у вас нет опции для буферизации строк! Он будет непрерывно передавать ваши данные из хвоста.

вот как вы используете grep

tail -f <file> | grep pattern

Вот как вы будете использовать awk

tail -f <file> | awk '/pattern/{print $0}'
  • 6
    Это не правильно; Awk из коробки выполняет буферизацию строки, как и большинство других стандартных инструментов Unix. (Более того, {print $0} является избыточным, поскольку печать является действием по умолчанию при выполнении условия.)
Сообщество Overcoder
Наверх
Меню