Perl从另一个变量的子串创建变量

时间:2014-03-27 14:23:15

标签: regex perl

我确信可以使用split()完成此操作,但如果可能,我更感兴趣的是使用s//。我想比较提供的IP地址和IP地址数组,并找到匹配(如果存在)。我还想考虑只有整个元素(不是数组元素的子串)匹配才能成功部分匹配。

例如:提供的IP:10.12.13.14

如果当前数组元素是10.12。或10.或10.12.13。我们可以考虑匹配,但不是10.12.11。

这是为了查找Linux主机上的hosts.allow TCP包装文件中是否存在给定的IP。如果文件中没有包含地址,我将添加附加地址的功能。由于部分子网匹配10.120。或192.168。工作,我也需要测试那些。这是我在下面缺少占位符“OR SUBSTRING MATCHES”的代码。我想知道my $IP = "1.2.3.4";如何创建子字符串变量,以便我可以在"1.2.3.""1.2."上执行字符串比较?

#PSEUDO CODE EXAMPLE
my @IPS = (10.12.13.14, 191.168.1.2, 10.8., 172.16. );
my $IP = "10.8.3.44";
foreach (@IPS) { if( $IP eq $_ || split(/\d+\./, 1-3, $IP) eq $_ ) { print $IP matches current IP: $_\n} 
# That split is supposed to represent "10." "10.8." and "10.8.3."  That is the logic I am trying to accomplish, but I would like to use s// if it fits the job, otherwise I am open to split() or other suggestions

#REAL CODE EXAMPLE  
#!/usr/bin/perl

my $IP = $ARGV[0];
my $FILE = '/etc/hosts.allow';

# Make sure it is an IP with either 157. or 140. as first octet

unless ( $IP =~ qr/(140|157)\.(\d{1,3}\.){2}\d{1,3}/ ) {
die "Usage: $0 IP Address" } else {
    open (FH, "<", "$FILE");
    foreach $LINE (<FH>) {
        if ( $LINE =~ qr/^sshd: (.*)/i ) {
            @LIST = split(", ", $1);
            foreach (@LIST) { 
                chomp $_;
                if($IP eq $_) || (OR SUBSTRING MATCHES ) <-need code here {
                    print "IP ADDRESS: $IP found! \n";
                } else { print "$_ is not a match\n"};
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

Why reinvent the wheel?

use strict;
use warnings;
use feature qw/say/;
use Net::Subnet;

my $allowed_hosts = subnet_matcher qw(
    10.8.0.0/16
    10.12.13.14/32
    191.168.1.2/32 
    172.16.0.0/16
);

for my $ip (qw/10.8.3.44/) {
    if ($allowed_hosts->($ip)) {
        say "$ip is allowed!";
    }
    else {
        say "$ip is disallowed!";
    }
}

答案 1 :(得分:1)

您可以构建正则表达式以匹配您接受的列表。正如M42已经演示的那样,您需要使用quotemeta,这样您的句号不会被视为任何字符。您还需要注意边界条件:

my @ips = qw(10.12.13.14 191.168.1.2 10.8. 172.16.);
my $ips_list = join '|', map {/\d$/ ? "$_\$" : $_} map quotemeta, @ips;
my $ips_re = qr{^(?:$ips_list)};

while (<DATA>) {
    chomp;
    if ($_ =~ $ips_re) {
        print "(pass) $_\n";
    } else {
        print "(fail) $_\n";
    }
}

__DATA__
10.8.3.44
999.10.8.999
10.12.13.14999
10.12.13.14
172.16.99.99
191.168.1.2
191.168.1.29

输出:

(pass) 10.8.3.44
(fail) 999.10.8.999
(fail) 10.12.13.14999
(pass) 10.12.13.14
(pass) 172.16.99.99
(pass) 191.168.1.2
(fail) 191.168.1.29

答案 2 :(得分:0)

怎么样:

if ( ($IP eq $_) || ($IP =~ /^\Q$_/) )  {