这段代码读取文件有什么问题?

时间:2013-10-16 12:56:56

标签: perl

我一直在尝试读取名为“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

3 个答案:

答案 0 :(得分:3)

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

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

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

如果正则表达式有效,我建议looks_like_number是多余的。我怀疑你使用它是因为==提供的内容类似isn't numeric in numeric eq (==),具体取决于您使用的perl版本。

答案 1 :(得分: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 $!;

答案 2 :(得分: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},当缺少数字时,这意味着尽可能多的次数。