2

我一直在尝试读取一个名为“perlthisfile.txt”的文件,它基本上是我计算机上 nmap 的输出。

我只想打印出 ip 地址,所以我编写了以下代码,但它不起作用:

#!/usr/bin/perl  
use strict;  
use warnings;  
use Scalar::Util qw(looks_like_number);

print"\n running \n";
open (MYFILE, 'perlthisfile.txt') or die "Cannot open file\n";

while(<MYFILE>) {
    chomp;
    my @value = split(' ', <MYFILE>);
    print"\n before foreach \n";
    foreach my $val (@value) {
        if (looks_like_number($val)) {
            print "\n looks like number block \n";
            if ($val == /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5})/) {
                print "\n$val\n";
            }
        }
    }
}
close(MYFILE);
exit 0;

当我运行这段代码时,输​​出是:

  running 
  before foreach 
  before foreach 
  looks like number block 
  before foreach 
  looks like number block 
  before foreach 
  looks like number block

我的 perlthisfile.txt:

  Starting Nmap 6.00 ( http://nmap.org ) at 2013-10-16 22:59 EST
  Nmap scan report for BoB2.iiNet (10.1.1.1)
  Nmap scan report for android-fbff3c3812154cdc (10.1.1.3)
  All 1000 scanned ports on android-fbff3c3812154cdc (10.1.1.3) are closed
  Nmap scan report for 10.1.1.5
  All 1000 scanned ports on 10.1.1.5 are open|filtered
  Nmap scan report for 10.1.1.6
  All 1000 scanned ports on 10.1.1.6 are closed
4

3 回答 3

3

这里有几个问题。正如@toolic 所说,<MYFILE>在内部调用split可能不是您想要的 - 它会从文件中读取下一条记录,$_而是使用。

此外,您正在使用==正则表达式,您应该使用绑定运算符,=~==仅用于Perl中的数字比较):

if ($val =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5})/){

如果正则表达式有效,我建议这looks_like_number是多余的。我怀疑您正在使用它,因为根据您使用的 perl 版本==给出了类似的东西。isn't numeric in numeric eq (==)

于 2013-10-16T13:07:38.427 回答
2

您有一些错误,其中一个是正则表达式,它应该有端口号的可选部分(:和以下\d{1,5}

#!/usr/bin/perl  
use strict;  
use warnings;  

open (my $MYFILE, '<', 'perlthisfile.txt') or die $!;

my $looks_like_ip = qr/( \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} (?: : \d{1,5})? )/x;
while (<$MYFILE>) {
    chomp;
    my @value = split;
    print"\n before foreach \n";
    foreach my $val (@value) {
      if (my ($match) = $val =~ /$looks_like_ip/){
        print "\n$match\n";
      }
      # else { print "$val doesn't contain IP\n" }
    }
}
close($MYFILE) or warn $!;
于 2013-10-16T13:14:15.793 回答
2

如果这就是它看起来的样子,这是一种提取 IP 的快速破解方法,那么您可能会使用一些简单的方法,例如:

perl -nlwe '/((?:\d+\.)+\d+)/ && print $1' perlthisfile.txt

也就是说,无论如何都不是一个非常严格的正则表达式,它只是匹配由句点连接的数字。如果您只想打印唯一的 IP,可以使用哈希来重复数据删除:

perl -nlwe '/((?:\d+\.)+\d+)/ && !$seen{$1}++ && print $1" perlthisfile.txt

使用更严格的正则表达式也匹配端口号:

perl -nlwe '/((?:\d+[\.:]){3,4}\d+)/ && print $1' perlthisfile.txt

这将不允许较短的数字链,并允许端口号。

最后一个正则表达式解释了:

/(         # opening parenthesis, starts a string capture
  (?:      # a non-capturing parenthesis
    \d+    # match a number, repeated one or more times
    [\.:]  # [ ... ] is a character class, it matches one of the literal 
           # characters inside it, and only one time
  ){3,4}   # closing the non-capturing parenthesis, adding a quantifier
           # that says this parenthesis can match 3 or 4 times
  \d+      # match one or more numbers
 )/x       # close capturing parenthesis (added `/x` switch)

/x开关只是为了让您可以按原样使用上面的正则表达式,带有注释和空格。

这背后的逻辑很简单:我们想要一个由数字后跟句点或冒号组成的字符串。我们想要这个字符串 3 或 4 次。以另一个数字结束。

和是量词+{3,4}它们指示它左侧的项目应该匹配多少次。默认情况下,每个项目都匹配一次,但通过使用量词,您可以更改它。+是 的简写{1,},你还有:

  • ? -> {1,0}
  • * -> {0,}

语法是{min,max},当缺少一个数字时,这意味着尽可能多的次数。

于 2013-10-16T13:34:46.573 回答