2017-09-01 51 views
3

我正在使用perl/mysql/iptables中的分布式fail2ban类似系统。Perl正则表达式 - 从maillog中提取ipv4

从/ var/log/messages中提取ipv4地址正在工作,但现在我想将/ var/log/maillog添加到汤中。

我有一个perl正则表达式:[1]

/ (?:25[]|2[0-4]\d|1?\d\d?)\. 
    (?:25[]|2[0-4]\d|1?\d\d?)\. 
    (?:25[]|2[0-4]\d|1?\d\d?)\. 
    (?:25[]|2[0-4]\d|1?\d\d?) /x 

而且从maillog中的线:

v817YjcU016645: 194.102.60.190.host.ifxnetworks.com [190.60.102.194] did not issue MAIL/EXPN/VRFY/ETRN during connection to MTA 

这里正则表达式同时匹配194.102.60.190 .host.ifxnetworks.com 和[ 190.60.102.194]

在我的代码中我有($ IP就是上面的正则表达式):

if ($line =~ m/($IP)/) 
{ 
    my ($ip) = $1; 

这里第一个匹配的IP般串中发现194.102.60.190 .host.ifxnetworks.com

那么,如何获取正则表达式忽略在.


结束一个IPv4

[1]为了可读性的Perl支持/x option

+1

您是否尝试过负向预测?就像'/...(?!\.)/' – zdim

+0

我认为IP地址之后的点只是问题的起点 – Wolf

+0

@zdim是的。匹配'194.102.60.19'0.host.ifxnetworks.com –

回答

4

如果这与negative lookahead

my ($ip) = $line =~ /($IP)(?![.\d])/; 

其作品为显示的数据是唯一的问题尝试。

由于$IP正则表达式中的最后一项允许通过\d?允许可变数量的数字,所以需要在前瞻中的字符类别[.\d]。因此单独使用(?!\.)时,引擎可以匹配少于1位的数字,然后剩下的数字可以满足限制条件的非.∗

因此,我们需要禁止.和数字,遵循该模式。


一个完整的程序

use warnings; 
use strict; 

my $t = 'a 194.102.60.190.host.ifxnetworks.com [190.60.102.194] b'; 

my $n = qr/(?:25[]|2[0-4]\d|1?\d\d?)/; 

my $IP = qr/$n\.$n\.$n\.$n/; 

my @m = $t =~ /($IP)(?![.\d])/g; 

print "@m\n"; 

打印190.60.102.194


∗考虑子字符串90.host。它的模式/\d\d?(?!\.)/工作如下。

第一\d比赛9。但接下来的一个,\d?,是可选的(非贪婪),它不匹配如果模式的其余部分就可以比拟的。事实上,(?!\.)看到以下0是不是.,所以我们一致90满足(?!\.)。整个模式(错误地)匹配

perl -wE'$_ = q(90.host); @m = /(\d)(\d?)(?!\.)(.)/; say for @m' 

打印

 
9 

0 

中间捕获组打着什么和下一个字符(.)0

现在考虑同样的子模式/\d\d?(?![.\d])/。该(?![.\d])要求,后面的内容既不是.也不一个数字。因此可选\d?被迫匹配下一个数字0。由于下一个字符,然后一个.模式失败。

随着(?![.\d])在单行而不是(?!\.)没有打印,因为模式根本不匹配。(在一些炮弹,你可能要逃跑!,所以(?\![.\d]),或使用脚本。)

所描述的发动机很可能不会去正是,这更是其操作的一个松散的描述。

+0

@MogensTrasherDK用完整的程序更新了答案 – zdim

+0

在这里使用'__DATA__'来更好地分离输入和程序不是更好吗? – Wolf

+0

@Wolf嗯,当有一些数据,我们想要一个完全自包含的程序,一个简单的演示(没有输入文件谈论等)。这里只是给出了一条线,并且它更简单(只读取数据等)。 – zdim

0

通常,正则表达式匹配WA在现有的字符序列中创建模式,如果存在不需要的东西,那么不匹配总是比较困难。

可以匹配的IP地址[1]被随后的非点([^.]):

(?:\d{1,3}\.){3}\d{1,3}[^.] 

和在该行的末尾($)IP地址:

(?:\d{1,3}\.){3}\d{1,3}$ 

您可以通过在未捕获组((?: ... ))中更改两个图案(|):

(?:\d{1,3}\.){3}\d{1,3}(?:[^.]|$) 

类似的问题可能是你下一个任务可以排除面前有一个点的IP地址,另外一个问题是,它也将在1.2.3.4.5匹配2.3.4.5,从而导致回我的介绍性发言...

我认为您尝试匹配的IP地址最好能找到一些能够检查周围字符的东西。具体说明一下。在开发阶段,尝试通过将匹配到“垃圾模式”来检查不匹配的行。在问题(其中,空格和括号内是可接受的环境)中所示的情况下,我建议使用

(?:[ \[]|^)((?:\d{1,3}\.){3}\d{1,3})(?:[ \]]|$) 

[1]我在这里使用的简化的正则表达式,即也匹配333.333.333.333000.000.000.000,当然可以改进以将匹配限制为有效的IP地址,但是对此的解决方案是abundant

+0

我认为解决方案是分两步进行提取。首先:'my($ line1)= $ line =〜/(\ [)($ IP)(\])/;'匹配'[190.60.102.194]'。其次:'我的($ ip)= $ line =〜/($ IP)/;'与我的意见中的'190.60.102.194' –

+0

@MogensTrasherDK两个阶段不是必要的,请参阅我的最新增加内容。实际匹配('((?:\ d {1,3} \。){3} \ d {1,3})')已包含在最后一个(“建议”)正则表达式中。 – Wolf

+0

@ MogensTrasherDK提醒一下:如果您(可能很快)在某些日志文件中遇到IP地址与其文本上下文之间的其他令人不安的交互作用,请回过头来看看您是否能够正确指定这些模式。 – Wolf