苦苦挣扎的基础知识 - Perl

时间:2015-12-21 11:59:57

标签: linux perl

我正在努力与Perl编写一个基本的解析器,并认为我会向大家寻求帮助。

所需的输出是过滤大文件,如下所示,查找“许可证:未知”的实例,并用逗号分隔带有“未知许可证”的设备的IP地址和主机名。

预期产出:

10.132.215.292,BOL03273D

____ DATA _____

spawn ssh -p 22 -c 3des -x -l bitops 10.132.215.292
bitops@10.132.215.292's password: 
register system.core2
BOL03273D # 
BOL03273D # terminal length 0
Unknown action 0
BOL03273D # terminal width 132
Unknown action 0
BOL03273D #  c v
ambiguous command before 'v'
Command fail. Return code 1
BOL03273D # edit root
Unknown action 0
BOL03273D # get webfilter status
Locale       : english
License      : Unknown
Expiration   : N/A
-=- Server List (Wed Dec 16 17:01:31 2015) -=-
IP                  Weight    RTT Flags  TZ    Packets  Curr Lost Total Lost
96.45.33.65             30    358        -8        127          0         49
209.222.147.36           0    427        -5        124          0         51
209.222.147.43           8    447        -5        130          0         57
64.26.151.36            16    468        -5        132          0         59
66.117.56.42            27    458        -5        135          0         62
66.117.56.37            45    497        -5        143          0         71
64.26.151.35            65    527        -5        143          0         70
69.195.205.102          91    507        -5        155          0         83
64.26.151.37           107    538        -5        157          0         85
96.45.33.64            128    397        -8        152          0         79
69.195.205.101         138    550        -5        164          0         92
62.209.40.74           141    627         1        160          0         89
208.91.112.196         158    417 D      -8        211          0        137
80.85.69.41            190    588         0        168          0         96
62.209.40.73           196    657         1        167          0         95
80.85.69.40            203    617         0        169          0         97
80.85.69.37            206    577         0        168          0         95
80.85.69.38            228    647         0        172          0         99
208.91.112.198         258    487 DI     -8        316          0        240
62.209.40.72           297    677         1        184          0        112
121.111.236.180        306    607         9        175          0        103
BOL03273D # 
BOL03273D #exit
Connection to 10.132.215.292 closed.
10.132.215.272
spawn ssh -p 22 -c 3des -x -l bitops 10.132.215.272
bitops@10.132.215.272's password: 
register system.core2
BOL00093D # 
BOL00093D # terminal length 0
Unknown action 0
BOL00093D # terminal width 132
Unknown action 0
BOL00093D #  c v
ambiguous command before 'v'
Command fail. Return code 1
BOL00093D # edit root
Unknown action 0
BOL00093D # get webfilter status
Locale       : english
License      : Contract
Expiration   : Fri Jun 26 19:00:00 2020
-=- Server List (Wed Dec 16 17:03:11 2015) -=-
IP                  Weight    RTT Flags  TZ    Packets  Curr Lost Total Lost
96.45.33.65             30     37        -8      28851          0        651
209.222.147.43           0     88        -5      16130          0        791
64.26.151.35             0    172        -5      15977          0        584
66.117.56.42             0     89        -5      16382          0       1065
66.117.56.37             0     89        -5      16382          0       1063
64.26.151.37             0    177        -5      15972          0        592
209.222.147.36           0     90        -5      16144          0        806
64.26.151.36             0    176        -5      15956          0        589
69.195.205.101           0    107        -5      16512          0       1150
69.195.205.102           0    107        -5      16470          0       1109
96.45.33.64             30     43        -8      27827          0        676
208.91.112.196          30     63 DI     -8      16687          0       1140
208.91.112.198          30    263 D      -8      17476          0       2089
80.85.69.38             50    167         0      15964          0        605
80.85.69.37             50    167         0      15961          0        602
80.85.69.41             50    168         0      15959          0        600
80.85.69.40             50    167         0      15980          0        621
62.209.40.73            60    198         1      16249          0        928
62.209.40.74            60    197         1      16278          0        959
62.209.40.72            60    197         1      16246          0        925
121.111.236.180        140    151         9      16147          0        786
121.111.236.179        140    160         9      16140          0        779
BOL00093D # 
BOL00093D #exit
Connection to 10.132.215.272 closed.
10.106.209.231

当前代码 -

$infile='final.log';
$outfile='License_Unknown.txt';
open(INPUT, $infile);
@data = <INPUT>;
close(INPUT);
open(OUTPUT, ">$outfile");

$siteid="";
$licensestate="";
$mgmtip="";


for ($i=0; $i <= $#data; ++$i)
{
   if ($data[$i] =~ /hntools/)
   {
    @line=split(/@/,$data[0])
    @sameline=split(/'/,$data[0])
    $mgmtip=$sameline[1];
    print OUTPUT "\n$mgmtip,";
   }

   if (($line[i] =~ /License      : Unknown/))
   {
        $siteid=$line[0];
        print OUTPUT " $siteid, ";
    }
    chomp $line[2];

}


close(OUTPUT);

2 个答案:

答案 0 :(得分:3)

好的,所以你的perl代码可以先做一点整理:

  • use strict;use warnings;置于顶部 - 它会产生更多错误,但它们会在以后咬你。
  • 您实际上并不需要像这样明确地迭代数组 - 除非您需要重复使用计数,否则不应该费心,而只需使用for (@array) {
  • 您可以按记录进行迭代,使用$/设置记录分隔符。看起来你可以使用“连接到”。
  • 您可以对所有当前记录进行模式匹配,默认情况下这样做。
  • 3个arg文件打开,带有词法文件句柄很好。例如open (my $output, '>', 'License_Unknown.txt' ) or die $!;
  • 正在测试它的返回码。

这样的事情可能吗?

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

#set record seperator
local $/ = 'Connection to';

#read files from either STDIN or specified on command line (like grep/sed etc.)
while (<>) {

    #select the first IP-like from the block. (This regex could
    #be better, but works for your sample).
    my ($ip) = m/\w+\@(\d+\.\d+\.\d+\.\d+)'s password/;

    #match the license line, and extract the value
    my ($license)  = m/License\s+:\s+(\w+)/;
    my ($hostname) = m/(\w+)\s+#/;

    #print both.
    next unless defined $license;
    print "$ip,$hostname\n" if $license eq 'Unknown';
}

输出

10.132.215.292,BOL03273D

$/是输入记录分隔符。通常它是一个换行符 - 所以perl一次迭代一行。但是您可以将其设置为多个字节或替代字符串 - 但不是正则表达式。在while循环中,perl读取它的输入,直到它到达该点(或文件末尾),然后将该块“馈送”到循环中。这就是为什么上面的工作 - 我们循环两次,但然后使用模式来挑选我们感兴趣的数据位。

你可以匹配其他元素 - 我抓住一个块中的第一个IP地址,但特别是该行:

bitops@10.132.215.292's password: 

你可以匹配:

m/bitops\@(\d+\.\d+\.\d+\.)'s password:/

虽然注意 - 匹配数字点数字等但如果你在那里有主机名,将不会匹配。 (包含字母)。

所以也许你想要:

m/bitops\@([\w\.]+)'s password:/

正则表达式中的各种元素总结在perldoc perlre中,但这是一个非常大的主题 - 正则表达式本身就是一种编程语言。

答案 1 :(得分:2)

这是一种替代解决方案,它使用状态变量而不是一次更改记录分隔符来读取块

很难从这么短的数据样本中确切地知道哪些地标可以可靠地用于导航。我假设每个块总是从以spawn开头并以主机IP地址结束的行开头,并以一行以Connection开头并以closed结尾的行结束。我也依赖于包含大写字母和小数位的主机名。我非常肯定我可以依赖License : Unknown

的格式

此程序需要输入文件的路径作为命令行参数

use strict;
use warnings 'all';

my ($ip, $host, $unknown);

while ( <> ) {

    if ( / (\d+\.\d+\.\d+\.\d+) .+ password /x ) {
        $ip = $1;
    }
    elsif ( / ^ ([A-Z0-9]+) \s+ # /x ) {
        $host //= $1;
    }
    elsif ( / ^ License \s+ : \s+ Unknown /x ) {
        $unknown = 1;
    }
    elsif ( / ^ Connection .+ closed /x ) {

        if ( $ip and $host and $unknown ) {
            print "$ip,$host\n";
        }

        ($ip, $host, $unknown) = (); # reset state variables
    }
}

输出

10.132.215.292,BOL03273D