У меня проблемы с обратными ссылками в awk.

^ и $не имеют значений (начало или конец строки )внутри [ ], которые используются для выбора группы символов. Внутри [ ]большинство операторов регулярных выражений теряют свое значение (, а некоторые символы приобретают особое значение или приобретают другое значение ). Ведущий ^в []означает, что группа инвертирована -соответствует всем , кроме этих символов. Таким образом, [^$]соответствует любому символу, кроме $. (И [$^]соответствуют только символам $и ^.)

Если вы хотите сопоставить начало или конец строки, используйте /^\|$/, где |равно или(необходимо экранировать в режиме регулярных выражений Vim по умолчанию ).

Так:

:%s/^\|$/'/g

gнеобходим, поскольку ^и $являются двумя независимыми совпадениями, а sпо умолчанию действует только на первое совпадение в строке.

1
21.10.2019, 10:22
2 ответа

icarus уже ответил на этот вопрос в awk, так что вот как извлечь дату и идентификатор в переменные, а данные события в хэш (ассоциативный массив )с помощьюperl:

#!/usr/bin/perl -l

use strict;

while(<>) {
  if (m/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}).+?\sID\s(\[\d{4}\]).*?Data -> (.*)$/) {
    my ($date,$id,$eventdata) = ($1,$2,$3);

    print $date;
    print $id;

    # decorate the key names with a tab (i.e. add a tab before each) 
    $eventdata =~ s/([^[:blank:]]+) *= */\t$1=/g;
    # remove tab from beginning of $eventdata
    $eventdata =~ s/^\t//;       #/

    # split $eventdata on tabs, and split again into key=value pairs
    # and store in %data hash.    
    my %data = map { my($k,$v) = split("=",$_,2); $k => $v } split(/ *\t/,$eventdata);

    foreach my $key (sort keys %data) { printf "%s=%s\n", $key, $data{$key} };
  };
};

(Комментарий #/предназначен только для исправления неработающей подсветки синтаксиса Perl U&L)

Обратите внимание, что ,2в конце операции split("=",$_,2)каждая пара ключ=значение разбивается максимум на два поля :все до первого=символ и все, что после него. Это означает, что не имеет значения, содержит ли значение символ =. Такие вещи гораздо проще сделать в perl, чем в awk. Работа с регулярными выражениями и группами захвата также упрощается, как показано в первых двух строках в начале цикла while(<>).

Сохранить как, например. kei.pl, сделайте его исполняемым с помощью chmod +x kei.plи запустите так:

$./kei.pl input 
2017-03-21T02:00:00
[4624]
AuthenticationPackageName=Negotiate
ImpersonationLevel=%%1122
IpAddress=10.0.0.0
IpPort=10.5.3.2
KeyLength=0
LmPackageName=Stainless
LogonGuid={00344000-0000-0000-0000-0000000003440}
LogonProcessName=Lxxoi
LogonType=8
ProcessId=0x0000000000000244
ProcessName=C:/Windows/System32/services.exe
SubjectDomainName=WORKGROUP
SubjectLogonId=0x00000000000004j7
SubjectUserName=PRETENDERS$
SubjectUserSid=S-1-5-18
TargetDomainName=NT AUTHORITY
TargetLogonId=0x00000000000003e7
TargetUserName=SYSTEMS
TargetUserSid=X-12-54-181
TransmittedServices=-
WorkstationName=-

Кстати, если вы хотите, чтобы дата и идентификатор также были в хеше, добавьте следующее после строки %data = map...(и удалите строки print $date;и print $id;:

$data{'DATE'} = $date;
$data{'ID'} = $id;
1
27.01.2020, 23:17

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

awk '{t=$1 ;$1=""; 
print gensub(/^.+?\sID\s(\[[0-9]{4}\]).+?\sTargetUserName\s=\s(.+?)\sTargetDomainName\s=\s(.+?)\sTargetLogonId\s=\s(.+?)\sLogonType\s=\s([0-9]{1,2})\s(.+?\sWorkstationName\s=\s(.+?)\sLogonGuid\s=\s.+?TransmittedServices\s=\s.+?\sLmPackageName\s=\s.+?KeyLength\s=\s.+?\sProcessId\s=\s.+?\sProcessName\s=\s.+?\sIpAddress\s=\s(.+?)\sIpPort\s\=\s([0-9]{1,}))?.+?$/,"\\4,\\3,\\2,\\1\\5" t ",\\7,\\8,","g") }'

Вы можете быть избирательным, поэтому у вас есть WorkstationName\s=\s(.+?)\sLogonGuidкак часть вашего шаблона, вы можете использовать

awk {t=$1; $1="" ; printf("%s", gensub(/^.+?WorkstationName\s=\s(.+?)\sLogonGuid.*$/,"\\1,")); printf("%s,", t)}

вытащить поле, и это можно повторить.

@cas отмечает в комментариях, что данные можно просматривать в 2 частях, материал до EventData/Data ->и материал после него, и что материал после него можно разделить на=(пространство равное пространство ). Я бы пошел дальше и рассмотрел его как пары ключ/значение и разделил на /\s\S+\s=\s/и использовал необязательный 4-й аргумент для split, чтобы получить ключи. В этом есть пара больших предположений, что пользователь не может поместить знак равенства в строку и что каждый фрагмент данных имеет ключ из одного слова. Обратите внимание, что индексы ключей и значений отличаются на 1, и что начальная часть строки заканчивается на v[1].

/usr/bin/awk '{
    n=split($0,v,/\s\S+\s=\s/,k)
    printf("There are %d fields\n",n)
    for(i=0;i<n;i++) { printf("%d key \"%s\" value \"%s\"\n",i,k[i],v[i+1]) }
}'

с вашими примерными данными дает

There are 22 fields
0 key "" value "2017-03-21T02:00:00 kornawesome Security/Microsoft-Windows-Security-Auditing ID [4624] :EventData/Data ->"
1 key " SubjectUserSid = " value "S-1-5-18"
2 key " SubjectUserName = " value "PRETENDERS$"
3 key " SubjectDomainName = " value "WORKGROUP"
4 key " SubjectLogonId = " value "0x00000000000004j7"
5 key " TargetUserSid = " value "X-12-54-181"
6 key " TargetUserName = " value "SYSTEMS"
7 key " TargetDomainName = " value "NT AUTHORITY"
8 key " TargetLogonId = " value "0x00000000000003e7"
9 key " LogonType = " value "8"
10 key " LogonProcessName = " value "Lxxoi  "
11 key " AuthenticationPackageName = " value "Negotiate"
12 key " WorkstationName = " value "-"
13 key " LogonGuid = " value "{00344000-0000-0000-0000-0000000003440}"
14 key " TransmittedServices = " value "-"
15 key " LmPackageName = " value "Stainless"
16 key " KeyLength = " value "0"
17 key " ProcessId = " value "0x0000000000000244"
18 key " ProcessName = " value "C:/Windows/System32/services.exe"
19 key " IpAddress = " value "10.0.0.0"
20 key " IpPort = " value "10.5.3.2"
21 key " ImpersonationLevel = " value "%%1122"

Отсюда вы можете пойти дальше, создать ассоциативный массив с именем say data

for(i=1;i<n;i++) {gsub(/[ =]/,"",k[i]);data[k[i]]=v[i+1]}

, а затем вы можете распечатать что-то вроде data["IpPort"], не беспокоясь о том, поле это 20 или 21.

3
27.01.2020, 23:17

Теги

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