从日志文件中提取特定值

时间:2017-09-07 11:12:06

标签: regex perl

我想使用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;

现在我想要正常表达式添加或以任何方式获取每行,网络地址和?之前的数字。

2 个答案:

答案 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,并以与以前相同的方式进行清理。