从maillog awk解析唯一的IP地址

时间:2010-11-17 00:15:09

标签: regex bash awk

昨天我在这里问了一个关于oneliner的问题,mjschultz给了我一个答案,我立刻爱上了:) Awk刚刚破坏了手头的任务,解析了一个大的日志文件(500+) MB)在几秒钟内。现在我正试图将我的其他oneliners移植到awk。

这是有问题的一个:

grep "pop3\[" maillog | grep "User logged in" |  
egrep -o '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}' | sort -u

我需要使用pop3连接到邮件服务器的所有唯一IP地址列表。

这是一个示例日志条目:

Nov 15 00:49:21 hostname pop3[19418]: login: [10.10.10.10] username plaintext  
User logged in

所以我找到所有包含“pop3”的行,并为“用户登录”部分解析它们。接下来我使用egrep和正则表达式来匹配IP地址,我使用sort来过滤掉重复的地址。

这是我到目前为止我的awk版本:

awk '/pop3\[.*.User logged in/ {ip[$7]=0} END {for (address in ip)  
{ print address} }' maillog

这非常有效,但并不总是所有日志条目都相同,例如有时IP会像这里一样移动到第8个字段:

Nov 15 10:42:40 hostname pop3[2232]: login: hostname.domain.com [20.20.20.20]  
username plaintext User logged in

使用awk捕获这些条目的最佳方法是什么?

一如既往地感谢你提前做出的所有好的回应,你已经教会了我很多:)

3 个答案:

答案 0 :(得分:3)

AWK代码

只是匹配你的ip格式...小心没有其他格式...

/pop3\[.*.User logged in/    {
         where = match($0,/\[[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
         if (where)
           ip[substr($0,RSTART+1,RLENGTH-1)]=0
} 

END {for (address in ip)  
{ print address} }  

ideone

运行

答案 1 :(得分:0)

对我来说,看起来更像Perl领域而不是Awk:

my %ip_addresses = ();
while (<>)
{
    next unless m/pop3\[/;
    next unless m/User logged in/;
    if (my($ip) = $_ =~ m/( \d{1,3} (?: [.] \d{1,3} ){3} )/msx)
    {
         $ip_addresses{$ip} = 1;
    }
}
foreach my $ip (sort keys %ip_addresses)
{
    print "$ip\n";
}

排序不完美 - 是字母而不是数字(所以192.1.168.10将出现在9.25.13.26之前)。当然,这可以修复。

答案 2 :(得分:0)

看到并尝试这些方法后,我得到了一个新想法。

belisarius的代码完成了我的要求,但由于它必须完成所有正则表达式的匹配,因此它不是最快的,速度就是我所追求的。

所以我想出了这个,因为你可以看到“有问题”的日志行有一个额外的字段,使它们全部13个字段长而不是正常的12,所以我只删除额外的字段,这给了我正确的IP地址列表,接下来我再次使用awk删除所有重复的条目:

awk '/pop3\[.*.User logged in/ {{if (NF == 13) $7="";gsub(FS "+",FS)};print $7}'
/var/log/maillog | awk '!($0 in a){a[$0];print}'

Ideone link如果您想查看实际操作中的代码