我有一个文件输入如下;
#volume stats
start_time 1
length 2
--------
ID
0x00a,1,2,3,4
0x00b,11,12,13,14
0x00c,21,22,23,24
volume stats
start_time 2
length 2
--------
ID
0x00a,31,32,33,34
0x00b,41,42,43,44
0x00c,51,52,53,54
volume stats
start_time 3
length 2
--------
ID
0x00a,61,62,63,64
0x00b,71,72,73,74
0x00c,81,82,83,84
#
我需要以下格式输出;
1 33 36 39 42
2 123 126 129 132
3 213 216 219 222
#
以下是我的代码;
#!/usr/bin/perl
use strict;
use warnings;
#use File::Find;
# Define file names and its location
my $input = $ARGV[0];
# Grab the vols stats for different intervals
open (INFILE,"$input") or die "Could not open sample.txt: $!";
my $date_time;
my $length;
my $col_1;
my $col_2;
my $col_3;
my $col_4;
foreach my $line (<INFILE>)
{
if ($line =~ m/start/)
{
my @date_fields = split(/ /,$line);
$date_time = $date_fields[1];
}
if ($line =~ m/length/i)
{
my @length_fields = split(/ /,$line);
$length = $length_fields[1];
}
if ($line =~ m/0[xX][0-9a-fA-F]+/)
{
my @volume_fields = split(/,/,$line);
$col_1 += $volume_fields[1];
$col_2 += $volume_fields[2];
$col_3 += $volume_fields[3];
$col_4 += $volume_fields[4];
#print "$col_1\n";
}
if ($line =~ /^$/)
{
print "$date_time $col_1 $col_2 $col_3 $col_4\n";
$col_1=0;$col_2=0;$col_3=0;$col_4=0;
}
}
close (INFILE);
#
我的代码结果是;
1
33 36 39 42
2
123 126 129 132
#
基本上,对于每个时间间隔,它只是汇总所有行的列,并显示每个时间间隔的所有列。
答案 0 :(得分:1)
$/
是你的朋友。尝试将其设置为''
以启用段落模式(用空行分隔数据)。
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = '';
while ( <> ) {
my ( $start ) = m/start_time\s+(\d+)/;
my ( $length ) = m/length\s+(\d+)/;
my @row_sum;
for ( m/(0x.*)/g ) {
my ( $key, @values ) = split /,/;
for my $index ( 0..$#values ) {
$row_sum[$index] += $values[$index];
}
}
print join ( "\t", $start, @row_sum ), "\n";
}
输出:
1 33 36 39 42
2 123 126 129 132
3 213 216 219 222
注意 - 使用制表位输出。如果您需要更灵活的选项,可以使用sprintf
。
我还建议代替:
my $input = $ARGV[0];
open (my $input_fh, '<', $input) or die "Could not open $input: $!";
你会更好:
while ( <> ) {
因为<>
是perl中的魔术文件句柄,所以 - 打开在命令行上指定的文件,并一次读取一个文件,如果没有,则读取STDIN
。这就像grep
/ sed
/ awk
这样做的方式。
因此,您仍然可以使用scriptname.pl sample.txt
运行此功能,或者您可以执行curl http://somewebserver/sample.txt | scriptname.pl
或scriptname.pl sample.txt anothersample.txt moresample.txt
另外 - 如果您想自己open
文件,最好使用词法变量和3 arg打开:
open ( my $input_fh, '<', $ARGV[0] ) or die $!;
你真的不应该使用像$col_1
这样的'编号'变量等。如果有数字,那么数组几乎总是更好。
答案 1 :(得分:1)
基本上,一个块以start_time
开头,以一行空格结束。如果相反,块的结尾始终确保为空行,则可以更改下面的测试。
使用arrays instead of variables with integer suffixes会很有帮助。
当您点击新块的开头时,记录start_time
值。当您点击统计行时,更新列总和,当您点击一行空格时,打印列总和并清除它们。
这样,您可以将程序的内存占用与最大输入行成比例,与最大输入块相对应。在这种情况下,没有太大的区别,但是,在现实生活中,可以有。您的原始程序将整个文件作为行列表读入内存,当使用大输入大小时,这些行将导致程序的内存占用量增加。
#!/usr/bin/env perl
use strict;
use warnings;
my $start_time;
my @cols;
while (my $line = <DATA>) {
if ( $line =~ /^start_time \s+ ([0-9]+)/x) {
$start_time = $1;
}
elsif ( $line =~ /^0x/ ) {
my ($id, @vals) = split /,/, $line;
for my $i (0 .. $#vals) {
$cols[ $i ] += $vals[ $i ];
}
}
elsif ( !($line =~ /\S/) ) {
# guard against the possibility of
# multiple blank/whitespace lines between records
if ( @cols ) {
print join("\t", $start_time, @cols), "\n";
@cols = ();
}
}
}
# in case there is no blank/whitespace line after last record
if ( @cols ) {
print join("\t", $start_time, @cols), "\n";
}
__DATA__
volume stats
start_time 1
length 2
--------
ID
0x00a,1,2,3,4
0x00b,11,12,13,14
0x00c,21,22,23,24
volume stats
start_time 2
length 2
--------
ID
0x00a,31,32,33,34
0x00b,41,42,43,44
0x00c,51,52,53,54
volume stats
start_time 3
length 2
--------
ID
0x00a,61,62,63,64
0x00b,71,72,73,74
0x00c,81,82,83,84
输出:
1 33 36 39 42 2 123 126 129 132 3 213 216 219 222
答案 2 :(得分:0)
当我运行你的代码时,我会收到警告:
Use of uninitialized value $date_time in concatenation (.) or string
我使用\s+
代替/ /
修复了它。
我还在循环后添加了print
,以防文件没有以空行结束。
这是最低限度更改的代码,用于生成所需的输出:
use strict;
use warnings;
# Define file names and its location
my $input = $ARGV[0];
# Grab the vols stats for different intervals
open (INFILE,"$input") or die "Could not open sample.txt: $!";
my $date_time;
my $length;
my $col_1;
my $col_2;
my $col_3;
my $col_4;
foreach my $line (<INFILE>)
{
if ($line =~ m/start/)
{
my @date_fields = split(/\s+/,$line);
$date_time = $date_fields[1];
}
if ($line =~ m/length/i)
{
my @length_fields = split(/\s+/,$line);
$length = $length_fields[1];
}
if ($line =~ m/0[xX][0-9a-fA-F]+/)
{
my @volume_fields = split(/,/,$line);
$col_1 += $volume_fields[1];
$col_2 += $volume_fields[2];
$col_3 += $volume_fields[3];
$col_4 += $volume_fields[4];
}
if ($line =~ /^$/)
{
print "$date_time $col_1 $col_2 $col_3 $col_4\n";
$col_1=0;$col_2=0;$col_3=0;$col_4=0;
}
}
print "$date_time $col_1 $col_2 $col_3 $col_4\n";
close (INFILE);
__END__
1 33 36 39 42
2 123 126 129 132
3 213 216 219 222