如何解析日志文件中的行?

0 投票
6 回答
1388 浏览
提问于 2025-04-17 03:49

我需要提取以下输出的值:

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的值存到一个变量里。我尝试过用shell脚本,但我的问题是,这个方法只有在日志条目的顺序每次都一样的时候才能工作。

所以,这个方法是行不通的:

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

6 个回答

1

你甚至不需要进行切割:

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

Python 让这个事情变得很简单。一个通用的解决方案,可以获取所有的 KEY=value 对,代码如下:

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的情况下做到这一点。你之前的思路是对的,但用正则表达式可以通过名字来搜索,而不是通过位置。

另外,你应该把$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

撰写回答