Греп от конца файла до начала

У меня есть файл с около 30.000.000 строк (Radius Accounting), и мне нужно найти последнее совпадение данного шаблона.

Команда:

tac accounting.log | grep $pattern 

дает то, что мне нужно, но это слишком медленно, потому что ОС должна сначала прочитать весь файл, а затем отправить в трубу.

Итак, мне нужно что-то быстрое, чтобы прочитать файл с последней строки до первой.

4 Solutions collect form web for “Греп от конца файла до начала”

tac помогает, если вы также используете grep -m 1 (при условии, что GNU grep ) имеет grep остановку после первого совпадения:

 tac accounting.log | grep -m 1 foo 

От man grep :

  -m NUM, --max-count=NUM Stop reading a file after NUM matching lines. 

В примере в вашем вопросе, как tac и grep необходимо обработать весь файл, поэтому использование tac является беспредметным.

Итак, если вы не используете grep -m , не используйте tac вообще, просто проанализируйте вывод grep чтобы получить последнее совпадение:

 grep foo accounting.log | tail -n 1 

Другой подход – использовать Perl или любой другой язык сценариев. Например (где $pattern=foo ):

 perl -ne '$l=$_ if /foo/; END{print $l}' file 

или

 awk '/foo/{k=$0}END{print k}' file 

Причина почему

 tac file | grep foo | head -n 1 

не останавливается в первом матче из-за буферизации.

Как правило, head -n 1 выходит после прочтения строки. Таким образом, grep должен получить SIGPIPE и выйти, как только он напишет вторую строку.

Но происходит то, что, поскольку его вывод не идет на терминал, grep его буферизирует. То есть, он не записывает его, пока он не накопился достаточно (4096 байт в моем тесте с GNU grep).

Это означает, что grep не выйдет, прежде чем он написал 8192 байта данных, поэтому, вероятно, довольно много строк.

С помощью GNU grep вы можете --line-buffered его, используя --line-buffered которая сообщает ему, что строки будут записываться, как только они будут найдены, независимо от того, идет ли он на терминал или нет. Таким образом, grep выйдет на вторую найденную строку.

Но с GNU grep любом случае вы можете использовать -m 1 вместо этого, как показал @terdon, что лучше, поскольку он выходит в первом матче.

Если ваш grep не является GNU grep , вы можете использовать sed или awk . Но tac является командой GNU, я сомневаюсь, что вы найдете систему с tac где grep не является GNU grep .

 tac file | sed "/$pattern/!d;q" # BRE tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE 

Некоторые системы имеют tail -r чтобы делать то же самое, что и GNU tac .

Обратите внимание, что для обычных файлов с возможностью поиска tac и tail -r эффективны, потому что они читают файлы в обратном порядке, они не просто полностью читают файл в памяти перед его печатью назад (как подход sed @ slm или tac на non -регулярные файлы).

В системах, где не доступны ни tac ни tail -r , единственными опциями являются реализация обратного чтения вручную с такими языками программирования, как perl или использование:

 grep -e "$pattern" file | tail -n1 

Или:

 sed "/$pattern/h;$!d;g" file 

Но это означает найти все матчи и только напечатать последний.

Вот возможное решение, которое найдет местоположение первого появления шаблона последним:

 tac -s "$pattern" -r accounting.log | head -n 1 

Это использует -s и -r переключатели tac которые заключаются в следующем:

 -s, --separator=STRING use STRING as the separator instead of newline -r, --regex interpret the separator as a regular expression 

Использование sed

Показывая некоторые альтернативные методы для прекрасного ответа @ Terdon с помощью sed :

 $ sed '1!G;h;$!d' file | grep -m 1 $pattern $ sed -n '1!G;h;$p' file | grep -m 1 $pattern 

Примеры

 $ seq 10 > file $ sed '1!G;h;$!d' file | grep -m 1 5 5 $ sed -n '1!G;h;$p' file | grep -m 1 5 5 

Использование Perl

В качестве бонуса здесь немного проще обозначить Perl:

 $ perl -e 'print reverse <>' file | grep -m 1 $pattern 

пример

 $ perl -e 'print reverse <>' file | grep -m 1 5 5 
  • Как извлечь количество физических процессоров и потоков на ядро? (Нет текста, только номер для использования в качестве входных данных в другом месте)
  • Добавьте возврат каретки к выходу `tail` при использовании` grep`
  • Периодически получать новые строки из файла, возможно, зависания
  • Можно ли изменить количество строк по умолчанию хвоста?
  • Tail -f передается через grep, не выводящий в файл, но выводит на консоль
  • Как заставить Vim вести себя как «tail -f»?
  • Как извлечь первую и последнюю строки в файле?
  • Можно ли «перевернуть» символическую ссылку на новый файл, не затрагивая никаких открытых дескрипторов файлов?
  • Файлы с изменением хвоста
  • Как я могу контролировать файл, который полностью воссоздается во время его запуска?
  • Tail Grep - печать окружающих линий до тех пор, пока шаблон не будет сопоставлен
  • Interesting Posts

    Поменять cron по умолчанию sendmail на почту

    Linux Сетевая маршрутизация на виртуальные IP-адреса из другой подсети

    Как сохранить псевдоним команды eval $ (other_comand)

    Как установить программное обеспечение на Red Hat?

    Возможно ли переключение рабочего пространства через Ctl + Alt + Arrow NON CYCLIC?

    Добавление публичного is_rsa.pub в known_hosts автоматически – как?

    Предотвращение или обнаружение действия каталога изменений в сценарии оболочки

    Для пересылки локального порта SSH для веб-трафика требуется настройка прокси-сервера в настройках браузера?

    Загрузка Debian на черный экран

    Существуют ли какие-либо утилиты для быстрого добавления, списка и удаления псевдонимов команд?

    Сложность создания регулярного выражения для поиска по меньшей мере двух вхождений символа в файл

    Как переустановить USB-накопитель после размонтирования Nautilus без его отсоединения?

    Плата Ethernet RealTek 8101E или аналогичная не работает на FreeBSD

    Установите Centos7 с файлом kickstart с «входом в аварийный режим»,

    Конфигурация терминала загрузки с моими заголовками

    Linux и Unix - лучшая ОС в мире.