Вопрос по pcre, windows, grep, batch-file, awk – соответствие регулярному выражению в файле журнала, возврат динамического содержимого выше и ниже соответствия

1

У меня есть несколько лог-файлов в следующем формате:

timestamp event summary
foo details
account name: userA
bar more details
timestamp event summary
baz details
account name: userB
qux more details
timestamp etc.

Я хотел бы найти файл журнала дляuserBи, если найден, эхо от предыдущей временной метки до (но не включая) следующей временной метки. Вероятно, будет несколько событий, соответствующих моему поиску. Было бы неплохо повторить какое-то--- start --- а также--- end --- окружая каждый матч.

Это было бы идеально дляpcregrep -M, право? Проблема в том, что у GnuWin32pcregrep происходит сбой при многострочном регулярном выражении при поиске больших файлов, и эти журналы регистрации могут составлять 100 мегабайт и более.

Что я'мы пытались

Мой хакерский обходной путь до сих пор включает использованиеgrep -B15 -A30 чтобы найти совпадающие строки и напечатать окружающий контент, а затем переместить теперь более управляемый кусок вpcregrep для полировки. Проблема в том, что некоторые события имеют длину менее десяти строк, а другие - 30 и более; и я'Я получаю некоторые неожиданные результаты, когда встречаются более короткие события.

:parselog  

set silent=1
set count=0
set deez=20\d\d-\d\d-\d\d \d\d:\d\d:\d\d
echo Searching %~2 for records containing %~1...

for /f "delims=" %%I in (
    'grep -P -i -B15 -A30 ":\s+\b%~1\b(@mydomain\.ext)?$" "%~2" ^| pcregrep -M -i "^%deez%(.|\n)+?\b%~1\b(@mydomain\.ext|\r?\n)(.|\n)+?\n%deez%" 2^>NUL'
) do (
    echo(%%I| findstr "^20[0-9][0-9]-[0-9][0-9]-[0-9][0-9].[0-9][0-9]:[0-9][0-9]:[0-9][0-9]" >NUL && (
        if defined silent (
            set silent=
            set found=1
            set /a "count+=1"
            echo;
            echo ---------------start of record !count!-------------
        ) else (
            set silent=1
            echo ----------------end of record !count!--------------
            echo;
        )
    )
    if not defined silent echo(%%I
)

goto :EOF

Есть лучший способ сделать это? Я'мы натолкнулись наawk Команда, которая выглядела интересно, что-то вроде:

awk "/start pattern/,/end pattern/" logfile

... но это также должно соответствовать средней схеме. К сожалению, Я'я не очень знаком сawk синтаксис. Какие-либо предложения?

Эд Мортон предложил мне привести пример регистрации и ожидаемый результат.

Пример всеобъемлющего

2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730158    Mon Mar 25 08:02:28 2013    529 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 2   Logon Failure:

    Reason:     Unknown user name or bad password

    User Name:  user5f

    Domain:     MYDOMAIN

    Logon Type: 3

    Logon Process:  Advapi  

    Authentication Package: Negotiate

    Workstation Name:   dc3

    Caller User Name:   dc3$

    Caller Domain:  MYDOMAIN

    Caller Logon ID:    (0x0,0x3E7)

    Caller Process ID:  400

    Transited Services: -

    Source Network Address: 169.254.7.86

    Source Port:    40838
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730159    Mon Mar 25 08:02:29 2013    680 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 9   Logon attempt by:   MICROSOFT_AUTHENTICATION_PACKAGE_V1_0

Logon account:  USER6Q

Source Workstation: dc3

Error Code: 0xC0000234
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730160    Mon Mar 25 08:02:29 2013    539 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 2   Logon Failure:

    Reason:     Account locked out

    User Name:  [email protected]

    Domain: MYDOMAIN

    Logon Type: 3

    Logon Process:  Advapi  

    Authentication Package: Negotiate

    Workstation Name:   dc3

    Caller User Name:   dc3$

    Caller Domain:  MYDOMAIN

    Caller Logon ID:    (0x0,0x3E7)

    Caller Process ID: 400

    Transited Services: -

    Source Network Address: 169.254.7.89

    Source Port:    55314
2013-03-25 08:02:32 Auth.Notice 169.254.5.62    Mar 25 08:36:38 DC4.mydomain.tld MSWinEventLog  5   Security    201326798   Mon Mar 25 08:36:37 2013    4624    Microsoft-Windows-Security-Auditing     N/A Audit Success   DC4.mydomain.tld    12544   An account was successfully logged on.

Subject:
    Security ID:        S-1-0-0
    Account Name:       -
    Account Domain:     -
    Logon ID:       0x0

Logon Type:         3

New Logon:
    Security ID:        S-1-5-21-606747145-1409082233-725345543-160838
    Account Name:       DEPTACCT16$
    Account Domain:     MYDOMAIN
    Logon ID:       0x1158e6012c
    Logon GUID:     {BCC72986-82A0-4EE9-3729-847BA6FA3A98}

Process Information:
    Process ID:     0x0
    Process Name:       -

Network Information:
    Workstation Name:   
    Source Network Address: 169.254.114.62
    Source Port:        42183

Detailed Authentication Information:
    Logon Process:      Kerberos
    Authentication Package: Kerberos
    Transited Services: -
    Package Name (NTLM only):   -
    Key Length:     0

This event is generated when a logon session is created. It is generated on the computer that was accessed.

The subject fields indicate...
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730162    Mon Mar 25 08:02:30 2013    675 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 9   Pre-authentication failed:

    User Name:  USER8Y

    User ID:        %{S-1-5-21-606747145-1409082233-725345543-3904}

    Service Name:   krbtgt/MYDOMAIN

    Pre-Authentication Type:    0x0

    Failure Code:   0x19

    Client Address: 169.254.87.158
2013-03-25 08:02:32 Auth.Critical   etc.

Пример команды

call :parselog user6q \\path\to\catch-all.log

Ожидаемый результат

---------------start of record 1-------------
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730159    Mon Mar 25 08:02:29 2013    680 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 9   Logon attempt by:   MICROSOFT_AUTHENTICATION_PACKAGE_V1_0

Logon account:  USER6Q

Source Workstation: dc3

Error Code: 0xC0000234
---------------end of record 1-------------


---------------start of record 2-------------
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730160    Mon Mar 25 08:02:29 2013    539 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 2   Logon Failure:

    Reason:     Account locked out

    User Name:  [email protected]

    Domain: MYDOMAIN

    Logon Type: 3

    Logon Process:  Advapi  

    Authentication Package: Negotiate

    Workstation Name:   dc3

    Caller User Name:   dc3$

    Caller Domain:  MYDOMAIN

    Caller Logon ID:    (0x0,0x3E7)

    Caller Process ID: 400

    Transited Services: -

    Source Network Address: 169.254.7.89

    Source Port:    55314
---------------end of record 2-------------
Дон»никогда не используюawk "/start pattern/,/end pattern/" logfile, Это делает банальные вещи немного короче, но вы можетеРасширить его, чтобы работать на нетривиальные вещи. Если вы опубликовали образец ввода (ям, если у вас есть фактические метки времени в вашем файле, а не слово "отметка времени») и ожидаемый результат, который поможет. Есть простое решение awk. Ed Morton

Ваш Ответ

4   ответа
1

Ниже приведено чистое пакетное решение, в котором не используется grep. Он находит линии меток времени, потому что "резюме" слово, которое не должно существовать в других строках, но при необходимости это слово может быть заменено на другое.

РЕДАКТИРОВАТЬ: Я изменил слово, которое идентифицирует временные метки на "Auth «.; Я также изменил FINDSTR стремиться игнорировать дела. Это новая версия:

@echo off
setlocal EnableDelayedExpansion

:parselog  
echo Searching %~2 for records containing %~1...

set n=0
set previousMatch=Auth.
for /F "tokens=1* delims=:" %%a in ('findstr /I /N "Auth\. %~1" %2') do (
   set currentMatch=%%b
   if "!previousMatch:Auth.=!" neq "!previousMatch!" (
      if "!currentMatch:Auth.=!" equ "!currentMatch!" (
         set /A n+=1
         set /A skip[!n!]=!previousLine!-1
      )
   ) else (
      set /A end[!n!]=%%a-1
   )
   set previousLine=%%a
   set previousMatch=%%b
)
if %n% equ 0 (
   echo No records found
   goto :EOF
)

if not defined end[%n%] set end[%n%]=-1
set i=1
:nextRecord
   echo/
   echo ---------------start of record %i%-------------
   if !skip[%i%]! equ 0 (
      set skip=
   ) else (
      set skip=skip=!skip[%i%]!
   )
   set end=!end[%i%]!
   for /F "%skip% tokens=1* delims=:" %%a in ('findstr /N "^" %2') do (
      echo(%%b
      if %%a equ %end% goto endOfRecord
   )
   :endOfRecord
   echo ---------------end of record %i%-------------
   set /A i+=1
if %i% leq %n% goto nextRecord

Пример команды:

C:>test user6q catch-all.log

Результат:

Searching catch-all.log for records containing user6q...

---------------start of record 1-------------
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730159    Mon Mar 25 08:02:29 2013    680 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 9   Logon attempt by:   MICROSOFT_AUTHENTICATION_PACKAGE_V1_0

Logon account:  USER6Q

Source Workstation: dc3

Error Code: 0xC0000234
---------------end of record 1-------------

---------------start of record 2-------------
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security    11730160    Mon Mar 25 08:02:29 2013    539 Security    NT AUTHORITY\SYSTEM N/A Audit Failure   dc3 2   Logon Failure:

    Reason:     Account locked out

    User Name:  [email protected]

    Domain: MYDOMAIN

    Logon Type: 3

    Logon Process:  Advapi  

    Authentication Package: Negotiate

    Workstation Name:   dc3

    Caller User Name:   dc3$

    Caller Domain:  MYDOMAIN

    Caller Logon ID:    (0x0,0x3E7)

    Caller Process ID: 400

    Transited Services: -

    Source Network Address: 169.254.7.89

    Source Port:    55314
---------------end of record 2-------------

Этот метод использует только одно выполнениеfindstr команда, чтобы найти все соответствующие записи, а затем еще однуfindstr Команда показать каждую запись. Обратите внимание, что сначалаfor /F ... команда работает надfindstr "Auth. user.." результаты, а второйfor /F Команда есть "пропустить = N», опция и GOTO, которые разрывают петлю, как только запись отображается. Это означает, что команды FOR не замедляют работу программы; скорость этой программы зависит от скорости команды FINDSTR.

Тем не менее, возможно, что второйfor /F "%skip% ... in ('findstr /N "^" %2') команда занимает слишком много времени, потому что размер результата вывода FINDSTR до его обработки в FOR. Если это произойдет, мы могли бы изменить второй FOR другим более быстрым методом (например, асинхронный канал, который будет разорван). Пожалуйста, сообщите результат.

Антонио

Я очень ценю работу, которую вы вложили в это. Резюме не делаетт на самом деле содержат слово "резюме" (который нене так много, как я могуfindstr /n "Auth."); но временная метка / итоговая строка не будут включать имя учетной записи, что является чем-то большим. rojo
@rojo: Могу я задать тебе простой запрос? Не могли бы вы выполнитьfindstr /I /N "Auth\. userXY" theBIGfile.log из командной строки и запишите время? Если это более 15 минут, то проблема со скоростью находится в самом FINDSTR, и мы ничего не можем с этим поделать! Aacini
@rojo: Показала ли моя программа "начало записи 1 " или нет? Если да, то у меня все еще есть надежда на ускорение! Aacini
+1, очень хорошая работа, очень быстрая с пустыми строками из записей, но без восклицательных знаков в выводе (DelayedExpansion). Мне нравится 'пропускать' трюк. Endoro
1

Это все, что вам нужно с GNU awk (для IGNORECASE):

$ cat tst.awk
function prtRecord() {
    if (record ~ regexp) {
        printf "-------- start of record %d --------%s", ++numRecords, ORS
        printf "%s", record
        printf "--------- end of record %d ---------%s%s", numRecords, ORS, ORS
    }
    record = ""
}
BEGIN{ IGNORECASE=1 }
/^[[:digit:]]+-[[:digit:]]+-[[:digit:]]+/ { prtRecord() }
{ record = record $0 ORS }
END { prtRecord() }

или с любым awk:

$ cat tst.awk
function prtRecord() {
    if (tolower(record) ~ tolower(regexp)) {
        printf "-------- start of record %d --------%s", ++numRecords, ORS
        printf "%s", record
        printf "--------- end of record %d ---------%s%s", numRecords, ORS, ORS
    }
    record = ""
}
/^[[:digit:]]+-[[:digit:]]+-[[:digit:]]+/ { prtRecord() }
{ record = record $0 ORS }
END { prtRecord() }

В любом случае вызапустить его в UNIX как:

$ awk -v regexp=user6q -f tst.awk file

Я нене знаю синтаксис Windows, но я ожидаюочень похожи, если не идентичны.

Обратите внимание на использование tolower () в скрипте, чтобы сделать обе стороны сравнения строчными, чтобы совпадение не учитывало регистр. Если вы можете вместо этого передать поисковое регулярное выражение, то 'это правильный случай, тогда вы неНе нужно вызывать tolower () с обеих сторон сравнения. NBD, это может просто немного ускорить сценарий.

$ awk -v regexp=user6q -f tst.awk file
-------- start of record 1 --------
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security
    11730159    Mon Mar 25 08:02:29 2013    680 Security    NT AUTHORITY\SYSTEM N/A Audit Failure
dc3 9   Logon attempt by:   MICROSOFT_AUTHENTICATION_PACKAGE_V1_0

Logon account:  USER6Q

Source Workstation: dc3

Error Code: 0xC0000234
--------- end of record 1 ---------

-------- start of record 2 --------
2013-03-25 08:02:32 Auth.Critical   169.254.8.110   Mar 25 08:02:32 dc3 MSWinEventLog   2   Security
    11730160    Mon Mar 25 08:02:29 2013    539 Security    NT AUTHORITY\SYSTEM N/A Audit Failure
dc3 2   Logon Failure:

    Reason:     Account locked out

    User Name:  [email protected]

    Domain: MYDOMAIN

    Logon Type: 3

    Logon Process:  Advapi

    Authentication Package: Negotiate

    Workstation Name:   dc3

    Caller User Name:   dc3$

    Caller Domain:  MYDOMAIN

    Caller Logon ID:    (0x0,0x3E7)

    Caller Process ID: 400

    Transited Services: -

    Source Network Address: 169.254.7.89

    Source Port:    55314
--------- end of record 2 ---------
Это то, чего я ожидал, но на практике этоочень медленно Я думаю я'я хотел бы придерживаться моей идеи использованияgrep с контекстом, а затем обрезать жир вокруг середины, какgrep Кажется, можно найти все совпадения в файле размером 100 мегабайт за несколько секунд. Тем не мение,awk кажется, повторяет все, что он получил через стандартный ввод отgrep, Интересно, есть ли gnuwin32?awk Безразлично»вести себя так же, как POSIX. Единственное, что я изменил вtst.awk были добавлены метки времени регулярное выражение (/^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/ вместо/timestamp/), и добавилIGNORECASE = 1 вprtRecord() rojo
Я чувствую глупость спрашивать, но как я могу добавить пару лишних пустых строк в конце--- end of record N --- линия? Я пытался добавить больше\nв конце тире,print "\n\n"printf "%s\n", "\n\n", настройкаORS = "\n\n\n" в пределахBEGIN раздел ... яя беспомощенprintf как я сawk по-видимому. rojo
ORS печатается в конце каждогоprint команда. Я никогда не пользоваласьprint в моем сценарии, поэтому установка ORS не будет иметь никакого эффекта. Добавление некоторых\nв конце тире должно быть все, что вам нужно сделать, я задаюсь вопросом, нужно ли вам, если это Windows, \ r \ n или что-то еще для создания новых строк. Чтобы быть в безопасности, вы можете напечатать ORS, и, надеюсь, это будет все, что вам нужно для создания новых строк в вашей ОС - я обновил свой скрипт выше, чтобы показать это. Ed Morton
Тестирование с файлом журнала, содержащим 2 902 930 строк, поиск завершается примерно за десять секунд, независимо от того, есть ли у меняIGNORECASE вBEGIN раздел, вprtRecord() функция, я используюtolower()или я не использую ничего из перечисленного и выполняю поиск с учетом регистра. Разница кажется незначительной. Для чего этоЯ думаю, я достаточно хорошо настроил свой матч, добавивregexp=":[[:space:]]+"regexp"[^[:alnum:]]" кBEGIN раздел. Я'Я должен проверить это еще немного, но я думаю, чтом на правильном пути сейчас. rojo
0

Я думаюAWK это все, что тебе нужно:

awk "/---start of record---/,/---end of record---/ {print}" logfile

Тот'Все, что вам нужно, если индикатор первой строки:

---start of record---

и последнее:

---end of record---

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

Один мудрец однажды сказал, что любовь - это все, что тебе нужно. В этом случае, однако, я думаю, что вы в основном скопировалиawk Линия, которую я имел в своем вопросе, игнорируя остальное. rojo
1

Вот'мои усилия:

@ECHO OFF
SETLOCAL
::
:: Target username
::
SET target=%1
CALL :zaplines
SET count=0
FOR /f "delims=" %%I IN (rojoslog.txt) DO (
  ECHO.%%I| findstr /r "^20[0-9][0-9]-[0-9][0-9]-[0-9][0-9].[0-9][0-9]:[0-9][0-9]:[0-9][0-9]" >NUL
  IF NOT ERRORLEVEL 1 (
    IF DEFINED founduser CALL :report
    CALL :zaplines
  )
  (SET stored=)
  FOR /l %%L IN (1000,1,1200) DO IF NOT DEFINED stored IF NOT DEFINED line%%L (
    SET line%%L=%%I
    SET stored=Y
   )
  ECHO.%%I|FINDSTR /b /e /i /c:"account name: %target%" >NUL
  IF NOT ERRORLEVEL 1 (SET founduser=Y)
)
IF DEFINED founduser CALL :report
GOTO :eof

::
:: remove all envvars starting 'line'
:: Set 'not found user' at same time
::
 :zaplines
(SET founduser=)
FOR /f "delims==" %%L IN ('set line 2^>nul') DO (SET %%L=)
GOTO :eof

:report
IF NOT DEFINED line1000 GOTO :EOF 
SET /a count+=1
ECHO.
ECHO.---------- START of record %count% ----------
FOR /l %%L IN (1000,1,1200) DO IF DEFINED line%%L CALL ECHO.%%line%%L%%
ECHO.----------- END of record %count% -----------
GOTO :eof
Спасибо Петру, и это хорошее усилие. К сожалению, этоСлишком медленно для меня, чтобы использовать. Я инициировал сценарий около 20 минут назад. С тех пор оба ядра моего процессора отскакивали на 70-100%, но сценарий все еще пытается перебрать первый файл журнала. Я нене думаю, что яВы сможете использовать чистый пакетный раствор. rojo

Похожие вопросы