Как мне анализировать строки из файла журнала?

#python #regex #perl #logfile

#python #регулярное выражение #perl #файл журнала

Вопрос:

Мне нужно извлечь значения следующего вывода:

 Oct  6 17:29:52 FW kernel: [ 5470.058450] ipTables: IN= OUT=eth0 SRC=192.168.1.116 DST=192.168.1.110 LEN=516 TOS=0x10 PREC=0x00 TTL=64 ID=4949 DF PROTO=TCP SPT=22 DPT=46216 WINDOW=446 RES=0x00 ACK PSH URGP=0
  

Мне нужно, например, значение PROTO, сохраненное в значении. пробовал shellscripting, моя проблема в том, что он работает, только если запись в журнале каждый раз находится в одном и том же порядке.

так что это не работает:

 while read line
do
        in_if=`echo $line | cut -d ' ' -f 10 | cut -d '=' -f 2`;
        out_if=`echo $line | cut -d ' ' -f 11 | cut -d '=' -f 2`;
        src_ip=`echo $line | cut -d ' ' -f 12 | cut -d '=' -f 2`;
        dst_ip=`echo $line | cut -d ' ' -f 13 | cut -d '=' -f 2`;
        pro=`echo $line | cut -d ' ' -f 20 | cut -d '=' -f 2`;
        echo "$in_if,$out_if,$src_ip,$dst_ip,$pro" >> output.csv;
done < $tmp_file
  

Комментарии:

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

Ответ №1:

Python делает это удобно. Общее решение, которое получает все пары КЛЮЧ = значение:

 import re
import fileinput

pair_re = re.compile('([^ ] )=([^ ] )')  # Matches KEY=value pair

for line in fileinput.input():  # The script accepts both data from stdin or a filename 

    line = line.rstrip()  # Removes final spaces and newlines
    data = dict(pair_re.findall(line))  # Fetches all the KEY=value pairs and puts them in a dictionary

    # Example of usage:
    print "PROTO =", data['PROTO'], "SRC =", data['SRC']  # Easy access to any value
  

Это, возможно, более разборчиво, гибко и удобно, чем сценарий оболочки.

Ответ №2:

Вы можете сделать это, не касаясь Perl. Вы были на правильном пути, но с регулярным выражением вы можете выполнять поиск по имени, а не по позиции.

Кроме того, вы должны заключать в кавычки $line, чтобы вас не сожгли какие-либо трубы или точки с запятой.

 pro=`echo "$line" | grep -o 'PROTO=w  ' | cut -d '=' -f 2`;
  

Конечно, если бы вы хотели использовать Perl, вы могли бы сделать гораздо более простое решение:

 #!/usr/bin/perl
while(<>) {
    /IN=(S*) .*OUT=(S*) .*SRC=(S*) .*DST=(S*) .*PROTO=(S*)/
       and print "$1,$2,$3,$4,$5n";
}
  

Затем вызовите:

 ./thatScript.pl logFile.txt >>output.csv
  

Ответ №3:

вам даже не нужно вырезать:

 grep -Po "(?<=PROTO=)w " yourFile
  

или

  sed -r 's/.*PROTO=(w ).*/1/' yourFile
  

или

 awk -F'PROTO=' '{split($2,a," ");print a[1]}' yourfile
  

тест:

 kent$  echo "Oct  6 17:29:52 FW kernel: [ 5470.058450] ipTables: IN= OUT=eth0 SRC=192.168.1.116 DST=192.168.1.110 LEN=516 TOS=0x10 PREC=0x00 TTL=64 ID=4949 DF PROTO=TCP SPT=22 DPT=46216 WINDOW=446 RES=0x00 ACK PSH URGP=0"|grep -Po "(?<=PROTO=)w "
TCP

kent$  echo "Oct  6 17:29:52 FW kernel: [ 5470.058450] ipTables: IN= OUT=eth0 SRC=192.168.1.116 DST=192.168.1.110 LEN=516 TOS=0x10 PREC=0x00 TTL=64 ID=4949 DF PROTO=TCP SPT=22 DPT=46216 WINDOW=446 RES=0x00 ACK PSH URGP=0"|sed -r 's/.*PROTO=(w ).*/1/'
TCP

kent$  echo "Oct  6 17:29:52 FW kernel: [ 5470.058450] ipTables: IN= OUT=eth0 SRC=192.168.1.116 DST=192.168.1.110 LEN=516 TOS=0x10 PREC=0x00 TTL=64 ID=4949 DF PROTO=TCP SPT=22 DPT=46216 WINDOW=446 RES=0x00 ACK PSH URGP=0"|awk -F'PROTO=' '{split($2,a," ");print a[1]}'
TCP
  

Ответ №4:

Простое решение на Perl может быть наиболее читаемым:

 #!/usr/bin/env perl

use strict; use warnings;

my $s = q{Oct  6 17:29:52 FW kernel: [ 5470.058450] ipTables: IN= OUT=eth0
SRC=192.168.1.116 DST=192.168.1.110 LEN=516 TOS=0x10 PREC=0x00 TTL=64
ID=4949 DF PROTO=TCP SPT=22 DPT=46216 WINDOW=446 RES=0x00 ACK PSH URGP=0};

while ($s =~ /(?<k> [A-Z] ) = (?<v> S*)/xg)  {
    print "'$ {k}' = '$ {v}'n";
}
  
C:Temp > z
'IN' = "
'OUT' = 'eth0'
'SRC' = '192.168.1.116'
'DST' = '192.168.1.110'
'LEN' = '516'
'TOS' = '0x10'
'PREC' = '0x00'
'TTL' = '64'
'ID' = '4949'
'PROTO' = 'TCP'
'SPT' = '22'
'DPT' = '46216'
'WINDOW' = '446'
'RES' = '0x00'
'URGP' = '0'

Вы также можете присвоить хэшу информацию в строке журнала:

 my %entry = ($s =~ /(?<k> [A-Z] ) = (?<v> S*)/xg);
  

Ответ №5:

В perl это должно сделать это

 #consider the $a variable has the log file my
$a = <<log file>>;
my $desired_answer;
#regex 
if ($a =~ m/PROTO=(.*?) /ig) 
{  $desired_answer=$1; }
  

Ответ №6:

спасибо за все ответы!

я выбрал способ написания шелла с использованием egrep и регулярных выражений…

 in_if=`echo "$line" | egrep -Eo 'IN=eth[0-9]*b' | cut -d '=' -f 2`;
out_if=`echo "$line" | egrep -Eo 'OUT=eth[0-9]*b' | cut -d '=' -f 2`;
src_ip=`echo "$line" | egrep -Eo 'SRC=[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | cut -d '=' -f 2`;
dst_ip=`echo "$line" | egrep -Eo 'DST=[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' | cut -d '=' -f 2`;
pro=`echo "$line" | grep -o 'PROTO=[A-Z]*b' | cut -d '=' -f 2`;