跟踪路由日志到CSV Perl解析器正则表达式问题

跟踪路由日志到CSV Perl解析器正则表达式问题,perl,Perl,我编写了一些shell脚本,它们运行到主机的跟踪路由,然后将它们保存到文件中。这项功能工作正常,并按预期将所有数据输出到.log文件 然后,我编写了一个简单的Perl脚本,将此.log转换为.csv文件,以便将其导入excel。然而,在查看生成的.csv文件时,我编写的Perl脚本在处理带有IP地址的数据包时出现了问题 例如,.log文件中的这一行被完美解析: 1139.222.0.1 0.941毫秒1.446毫秒1.996毫秒 进入.csv文件,如下所示: 1139.222.0.1,0.941

我编写了一些shell脚本,它们运行到主机的跟踪路由,然后将它们保存到文件中。这项功能工作正常,并按预期将所有数据输出到
.log
文件

然后,我编写了一个简单的Perl脚本,将此
.log
转换为
.csv
文件,以便将其导入excel。然而,在查看生成的
.csv
文件时,我编写的Perl脚本在处理带有IP地址的数据包时出现了问题

例如,
.log
文件中的这一行被完美解析:

1139.222.0.1 0.941毫秒1.446毫秒1.996毫秒

进入
.csv
文件,如下所示:

1139.222.0.1,0.941毫秒,1.446毫秒,1.996毫秒

但是,如果traceroute返回存储在
.log
文件中的与此类似的内容:

12154.54.57.98 7.579 ms 154.54.74.42 7.009 ms 130.117.0.58 7.480 ms

然后它被错误地解析到
.csv
文件中,并破坏以下整个
.csv
文件(这是一个虚构的示例):

11213.248.77.134,7.432毫秒,9.038毫秒,213.248.70.238毫秒

正如您所看到的,带有跃点时间的IP现在被用作数据包所用的时间

我很困惑如何解决这个问题!如果您有任何帮助,我们将不胜感激。下面是一段代码片段,它可以将每个跃点的日志转换为csv:

  my $start = "'Hop','IP','T1','T2','T3'";
  print OUTPUT "\n$_$start\n";
 };

  print OUTPUT "$1,$2,$3 ms,$4 ms,$5 ms\n" if (/(\d+)\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+ms\s+(\S+)/);
编辑

编写了我自己的修复程序,添加了额外的csv列并适当地插入其中

  my $start = "'Hop','IP','T1','T1IP','T2','T2IP',T3'";
  print OUTPUT "\n$_$start\n";
 };

 if (/(\d+)\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+ms\s+(\S+)\s+ms/){
 print OUTPUT "$1,$2,$3 ms, ,$4 ms, ,$5 ms\n";

}elsif (/(\d+)\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+ms/){
 print OUTPUT "$1,$2,$3 ms,$4,$5 ms, ,$6 ms\n";

}elsif (/(\d+)\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+ms\s+(\S+)\s+(\S+)\s+ms/){
 print OUTPUT "$1,$2,$3 ms, ,$4 ms,$5,$6 ms\n";

}elsif (/(\d+)\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+(\S+)\s+ms\s+(\S+)\s+(\S+)\s+ms/){
 print OUTPUT "$1,$2,$3 ms,$4,$5 ms,$6,$7 ms\n";
};

感谢您的帮助/回复

对于您显示的数据,我只需将行拆分为空格,后面不跟
ms

my $csv = join ',', split /\s+(?!ms)/, $line;
但是,您显示的代码暗示跟踪路由信息与日期混在一起,因此这可能不合适

更新

看过你的数据后,我认为这应该是你想要的

请注意,打印的标头名称与行中有多个IP地址的数据不对应。我不知道在那种情况下你想做什么

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

my $logfile    = 'trace.log';
my $parsedfile = 'trace.csv';

open my $infh,  '<', $logfile;
open my $outfh, '>', $parsedfile;

while (<$infh>) {
    if (/^[a-z]{3}\s+[a-z]{3}/i) {
        print $outfh $_;
        print $outfh qq{"Hop","IP","T1","T2","T3"\n};
    }
    elsif (/^\s*\d/) {
        chomp;
        s/^\s+//;
        print $outfh join(',', split /\s+(?!ms)/), "\n";
    }
}

猜测您想要什么,不带标题代码:

my $re_ip = qr/\d+\.\d+\.\d+\.\d+/;
while(<INPUT>) {
  my @v = split(/($re_ip)/);
  my $hop = (shift(@v) =~ /(\d+)/)[0]; # the hop number?
  for my $v (@v) {
    if ($v =~ /$re_ip/) {
      print OUTPUT "$hop,$v,";
    } else {
      my @ms = $v =~ /(\S+\s+ms)/g;
      print OUTPUT join(",", @ms), "\n";
    }   
  }
}
my$re\u ip=qr/\d+\.\d+\.\d+\.\d+/;
while(){
my@v=拆分(/($re_ip)/);
我的$hop=(shift(@v)=~/(\d+/)[0];#跳数是多少?
我的$v(@v){
如果($v=~/$re\u ip/){
打印输出“$hop,$v”;
}否则{
my@ms=$v=~/(\S+\S+ms)/g;
打印输出联接(“,”,@ms),“\n”;
}   
}
}

请显示不工作的代码如果(/(\d+)\s+(\s+)\s+(\s+)\s+(\s+)\s+(\s+)\s+(\s+)\s+(\s+)\s+ms+(\s+),则不工作的代码为打印输出“$1、$2、$3 ms、$4 ms、$5 ms\n”;因为这只解释了如果跟踪路由只返回时间值,而不返回时间和IP值,那么日期只是作为标题,并且在日志/csv文件的开头只打印一次,因为此跟踪路由重复运行,我需要它作为参考,traceroute启动后,将不会打印其他日期:)谢谢您的回复,我将研究该方法谢谢您更好地理解了您的问题,我认为我的解决方案可能不合适。一个完整输入的示例将很有帮助。谢谢Ben。我已经更新了我的答案,以提供我认为有效的程序这正是我一直在尝试的,我使用一系列elsif语句创建了一个类似的程序,但是这只起了一半的作用,您的代码更整洁、更容易理解。非常感谢你!还添加了我自己对原始问题的回答,以处理标题问题:)再次感谢!谢谢你的回复,我也来看看这个:)
my $re_ip = qr/\d+\.\d+\.\d+\.\d+/;
while(<INPUT>) {
  my @v = split(/($re_ip)/);
  my $hop = (shift(@v) =~ /(\d+)/)[0]; # the hop number?
  for my $v (@v) {
    if ($v =~ /$re_ip/) {
      print OUTPUT "$hop,$v,";
    } else {
      my @ms = $v =~ /(\S+\s+ms)/g;
      print OUTPUT join(",", @ms), "\n";
    }   
  }
}