Python-версия grep -A (и -B и -C с окружающими строками / контекстом) - PullRequest
0 голосов
/ 15 сентября 2018

Я ищу версию grep с малой сложностью для Python, в частности, grep -C <context> (или, альтернативно, grep -B <before-context> -A <after-context>).

У меня есть модуль поиска grep, соответствующий только что найденной строке.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@file bbd025_pygrep.py

import re

def grep(string_to_find, filename):
  the_result_str = ''

  with open(filename, 'r') as f:
    lines = f.readlines()

  for line in lines:
    if re.match(string_to_find, line):
      the_result_str += line + "\n"

  return the_result_str

##endof:  grep(string_to_find, filename)

Моя ситуация сейчас такова, что у меня есть файл длиной 1386257 строк - лог-файл для записей базы данных. Я анализирую его для сбора различной информации об одной записи в базе данных за раз. На данный момент мой процесс состоит в grep одной строке, такой как

Feb 29 10:06:37 - [159|x|x|x|x|x],[x|x|x|x],DB_INSERT,DB_ID=137

Используя значение 159, я выполняю четыре других grep s, чтобы получить всю необходимую информацию о записи в базе данных.

Проблема в том, что при более чем 1 Mline пять отдельных grep стоят дорого. Одна приятная вещь - для каждой записи есть только одна строка, такая как предыдущая. Однако остальные четыре строки не всегда располагаются одинаково относительно первой. Если я использую сокращение, то указанная выше строка обозначается

line2_entry137

и еще одна строка, соответствующая той же записи

Feb 29 10:06:37 - [159|15|x|x|x|x],[unknown|x|7|1.2.3.4],ACTION_BEGIN,USER_INFO

обозначается

line3_entry137

Я могу получить такие ситуации, как

line1_entry137
line5_entry135
line2_entry137
line3_entry136
line3_entry137
line1_entry138
line2_entry138
line4_entry137
line3_entry138
line4_entry138
line4_entry136
line5_entry138
line5_entry138
line5_entry137

Выше для краткости я показал, что есть также line1, line4 и line5 для entry137. Это для пяти grep с. В действительности, существуют также значения от line6 до line20, которые соответствуют моему значению 159 и соответствуют entry137.

Однако я определил, что в подавляющем большинстве случаев (я надеюсь, что во всех случаях) вся информация для entry137 находится в пределах 50 строк от line2.

Если бы я просто использовал bash (что я не могу - вещи компании), я мог бы радикально сократить время поиска. Я покажу это с помощью ряда команд (где я не включаю весь вывод.)

$ time grep "DB_INSERT\,DB_ID\=137$" /my/path/logfile.log
Feb 29 10:06:37 - [159|x|x|x|x|x],[x|x|x|x],DB_CALL_INSERT,DB_ID=137

real    0m1.708s
user    0m0.078s
sys     0m0.046s

# because such a line only appears once
$ time grep -m 1 "DB_INSERT\,DB_ID\=137$" /my/path/logfile.log
Feb 29 10:06:37 - [159|x|x|x|x|x],[x|x|x|x],DB_CALL_INSERT,DB_ID=137

real    0m0.171s
user    0m0.000s
sys     0m0.046s

$ time grep -m 1 -B 50 -A 50 "DB_INSERT\,DB_ID\=137$" /my/path/logfile.log > /dev/null

real    0m0.157s
user    0m0.031s
sys     0m0.030s

Я знаю, что могу реализовать деталь -m 1, используя break из моего for line in lines цикла. Однако я не знаю, как реализовать команду -A или -B (или, что то же самое, -C) в Python. Я не знаю, как "вернуться" или "опередить" линию, на которой я нахожусь.

Основные шаги после этого будут следующие:

$ pertinent_line=$(grep -m 1 "DB_INSERT\,DB_ID\=137$" /my/path/logfile.log)

# parse out the date and the '159'

$ pertinent_stuff=$(grep -m 1 -C 50 "DB_INSERT\,DB_ID\=137$" /my/path/logfile.log)

$ info3=$(echo "${pertinent_stuff}" | grep "^Feb 29.*\[159.*USER_INFO$"

$ echo "$(info3)"
Feb 29 10:06:37 - [159|15|x|x|x|x],[unknown|x|7|1.2.3.4],ACTION_BEGIN,USER_INFO

$ # etc. with greps for the other 3 lines

Как мне добавить context материал в мой Python grep?

P.S. Моя работа над этим заключалась в том, чтобы выяснить, как реализовать grep в Python, как это видно. Я не уверен, куда пойти для отдыха.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...