我想使用Perl在日志文件的同一行中提取两个值。
Network Next Hop metric locprf Path
*|i10.1.5.0/24 10.6.76.242 2 100 0 65000?
*|i10.1.9.0/24 10.6.76.242 2 100 0 64345 63800?
*|i10.2.9.0/25 10.6.76.242 2 100 0?
对于每一行,我想提取?
我有这个,但它只提取网络地址。
open( CONF, '<', 'putty-wan.log' ) or die "\n";
my @ip;
open( FICHE, ">RouterNetwork.txt" ) || die ( "Vous ne pouvez pas créer le fichier \"RouterNetwork.txt\"" );
while ( my $line = <CONF> ) {
if ( $line =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2})/ ) {
print FICHE $1, "\n";
}
}
close(FICHE);
close CONF;
现在我想要正常表达式添加或以任何方式获取每行,网络地址和?
之前的数字。
答案 0 :(得分:0)
没有什么特别要做的,只是继续使用您要捕获的数字进行线描述:
use strict;
use warnings;
open (my $conf, '<', 'putty-wan.log') || die "Don't eat too much Montbéliard saussages\n";
open (my $output, '>', 'RouterNetwork.txt') || die ('Vous ne pouvez pas créer le fichier "RouterNetwork.txt"');
while( <$conf> ) { # the current line is stored in $_
print $output "$1\t$2\n" if /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}).*\b(\d+)\?/;
}
close $output;
close $conf;
注意数字前的单词边界,以确保获得整数而不是最后一位数。
模式也可缩短为:/([\d.]{7,15}\/\d\d?).*?(\d+)\?/
注意不要使用旧式编程风格并查看perl当前的实践。 (系统地使用严格和警告)
请注意,对于日志文件,字段接近(按空格划分行)有时更方便。
答案 1 :(得分:0)
如果显示格式,您可以使用
处理该行my ($ip, $n) = map { s/^\D*|\D*$//gr } (split ' ', $line)[0,-1];
或,当该行位于$_
variable
my ($ip, $n) = map { s/^\D*|\D*$//gr } (split)[0,-1];
使用/r
非破坏性修饰符返回新字符串(保持原始字符不变,我们在此不关心)。它从v5.16开始提供。如果您的Perl版本较旧,请使用
my ($ip, $n) = map { s/^\D*|\D*$//g; $_ } (split)[0,-1];
至于处理整个文件,您需要一种方法来检测标题行。如何执行此操作取决于文件格式的详细信息。给定样本,也许跳过以字母开头的单词
use warnings;
use strict;
use feature 'say';
my $file = 'putty-wan.log';
open my $fh, '<', $file or die "Can't open $file: $!";
while (<$fh>)
{
next if /^[a-zA-Z]+\b/;
my ($ip, $num) = map { s/^\D*|\D*$//gr } (split)[0,-1];
say "$ip $num";
}
一些评论
请始终以use warnings;
开头,并use strict;
使用open
的三参数形式,带有词法文件句柄。它更好
始终在$!
语句中加入die
,以查看实际错误。这将是“默认”的方式,有时也需要其他error variables。
尽管使用||
并没有任何问题,or
对于流量控制来说非常方便,precedence适当降低。但最重要的是,无论如何都要保持一致。
有人澄清说,该行的最后一部分也可以是6500 ?
或65000 i
等。
然后将所有字段存储在数组中并从后面处理它,查找带数字的第一个字段。
while (<$fh>)
{
next if /^[a-zA-Z]+\b/;
my @fields = split;
my $ip = (shift @fields) =~ s/^\D*//gr; #/# need v5.16 for /r
my $num;
while (my $f = pop @fields) {
($num) = $f =~ /(\d+)/;
last if $num;
}
say "$ip $num";
}
仍然从第一个字段获取IP,并以与以前相同的方式进行清理。