Perl Regex - 从邮件日志中提取 ipv4
Perl Regex - extracting ipv4 from maillog
我正在 perl/mysql/iptables 中开发类似 fail2ban 的分布式系统。
正在从 /var/log/messages 中提取 ipv4 地址,但现在
我想在汤里加/var/log/maillog
我有一个 perl 正则表达式:[1]
/ (?:25[012345]|2[0-4]\d|1?\d\d?)\.
(?:25[012345]|2[0-4]\d|1?\d\d?)\.
(?:25[012345]|2[0-4]\d|1?\d\d?)\.
(?:25[012345]|2[0-4]\d|1?\d\d?) /x
邮件日志中的一行:
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) = ;
这里找到第一个匹配的类似 ip 的字符串 194.102.60.190
.host.ifxnetworks.com
那么,如何让正则表达式忽略以 .
结尾的 ipv4
[1] 为了便于阅读,Perl 支持 /x option
一般来说,正则表达式匹配现有字符序列中想要的模式,如果存在不需要的东西,则不匹配总是有点困难。
您可以匹配后跟非点 ([^.]
):
的 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 地址最好通过同时检查周围字符的东西找到。具体一点。对于开发阶段,尝试通过将它们匹配到 "garbage patterns" 来检查不匹配的行。在问题中显示的情况下(空格和括号是可接受的环境),我建议使用
(?:[ \[]|^)((?:\d{1,3}\.){3}\d{1,3})(?:[ \]]|$)
[1] 我这里使用了一个简化的正则表达式,它也匹配 333.333.333.333
或 000.000.000.000
,当然可以改进限制匹配到有效的 IP 地址,但解决方案是 abundant.
如果这是唯一的问题,请尝试 negative lookahead
my ($ip) = $line =~ /($IP)(?![.\d])/;
适用于显示的数据。
前瞻 [.\d]
中的字符 class 是必需的,因为 $IP
正则表达式中的最后一项通过 \d?
允许可变数量的数字.因此,单独使用 (?!\.)
引擎可以匹配的数字比现有数字少一位,然后剩余的数字满足非 .
限制。†
因此我们需要禁止 .
和模式后面的数字。
一个完整的程序
use warnings;
use strict;
my $t = 'a 194.102.60.190.host.ifxnetworks.com [190.60.102.194] b';
my $n = qr/(?:25[012345]|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
不是 .
,因此我们匹配 9
并且 0
满足 (?!\.)
。整个模式(错误地)匹配
perl -wE'$_ = q(90.host); @m = /(\d)(\d?)(?!\.)(.)/; say for @m'
打印
9
0
中间的捕获组什么也没捕获,下一个字符 (.)
是 0
.
现在考虑相同子字符串的模式 /\d\d?(?![.\d])/
。 (?![.\d])
要求后面的不是 .
也不是 数字。因此,可选的 \d?
被迫匹配下一个数字 0
。由于下一个字符 是 一个 .
模式失败。
在上面的单行测试中使用 (?![.\d])
而不是 (?!\.)
没有打印任何内容,因为模式根本不匹配。 (在某些 shell 中,您可能必须转义 !
,因此 (?\![.\d])
,或使用脚本。)
引擎可能不会像描述的那样完全,这更像是对其操作的粗略描述。
我正在 perl/mysql/iptables 中开发类似 fail2ban 的分布式系统。
正在从 /var/log/messages 中提取 ipv4 地址,但现在 我想在汤里加/var/log/maillog
我有一个 perl 正则表达式:[1]
/ (?:25[012345]|2[0-4]\d|1?\d\d?)\.
(?:25[012345]|2[0-4]\d|1?\d\d?)\.
(?:25[012345]|2[0-4]\d|1?\d\d?)\.
(?:25[012345]|2[0-4]\d|1?\d\d?) /x
邮件日志中的一行:
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) = ;
这里找到第一个匹配的类似 ip 的字符串 194.102.60.190
.host.ifxnetworks.com
那么,如何让正则表达式忽略以 .
[1] 为了便于阅读,Perl 支持 /x option
一般来说,正则表达式匹配现有字符序列中想要的模式,如果存在不需要的东西,则不匹配总是有点困难。
您可以匹配后跟非点 ([^.]
):
(?:\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 地址最好通过同时检查周围字符的东西找到。具体一点。对于开发阶段,尝试通过将它们匹配到 "garbage patterns" 来检查不匹配的行。在问题中显示的情况下(空格和括号是可接受的环境),我建议使用
(?:[ \[]|^)((?:\d{1,3}\.){3}\d{1,3})(?:[ \]]|$)
[1] 我这里使用了一个简化的正则表达式,它也匹配 333.333.333.333
或 000.000.000.000
,当然可以改进限制匹配到有效的 IP 地址,但解决方案是 abundant.
如果这是唯一的问题,请尝试 negative lookahead
my ($ip) = $line =~ /($IP)(?![.\d])/;
适用于显示的数据。
前瞻 [.\d]
中的字符 class 是必需的,因为 $IP
正则表达式中的最后一项通过 \d?
允许可变数量的数字.因此,单独使用 (?!\.)
引擎可以匹配的数字比现有数字少一位,然后剩余的数字满足非 .
限制。†
因此我们需要禁止 .
和模式后面的数字。
一个完整的程序
use warnings;
use strict;
my $t = 'a 194.102.60.190.host.ifxnetworks.com [190.60.102.194] b';
my $n = qr/(?:25[012345]|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
不是 .
,因此我们匹配 9
并且 0
满足 (?!\.)
。整个模式(错误地)匹配
perl -wE'$_ = q(90.host); @m = /(\d)(\d?)(?!\.)(.)/; say for @m'
打印
9 0
中间的捕获组什么也没捕获,下一个字符 (.)
是 0
.
现在考虑相同子字符串的模式 /\d\d?(?![.\d])/
。 (?![.\d])
要求后面的不是 .
也不是 数字。因此,可选的 \d?
被迫匹配下一个数字 0
。由于下一个字符 是 一个 .
模式失败。
在上面的单行测试中使用 (?![.\d])
而不是 (?!\.)
没有打印任何内容,因为模式根本不匹配。 (在某些 shell 中,您可能必须转义 !
,因此 (?\![.\d])
,或使用脚本。)
引擎可能不会像描述的那样完全,这更像是对其操作的粗略描述。