我正在努力与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);
答案 0 :(得分:3)
好的,所以你的perl代码可以先做一点整理:
use strict;
和use warnings;
置于顶部 - 它会产生更多错误,但它们会在以后咬你。 for (@array) {
。 $/
设置记录分隔符。看起来你可以使用“连接到”。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