2011-10-06 44 views
0

我需要提取以下的輸出的值:如何解析日誌文件中的行?

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 
+0

你爲什麼取消接受我的答案嗎?不要成爲妓女的名聲,但是當你這樣做時,我們都會失分。 – Chriszuma

回答

1

你可以這樣做不接觸的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,$5\n"; 
} 

然後調用:

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

你甚至不需要剪切:

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

OR

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

OR

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 
0

在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; } 
4

Python做這個方便。獲得所有KEY =值對的一般解決方案是:

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 

這可以說比shell腳本更清晰,更靈活和更方便。

1

一個簡單的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); 
0

感謝所有答覆!

我選擇使用egrep的正則表達式和的shellscripting的方式......

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`;