awk 或 Perl 修改数据

awk or Perl to modify data

使用下面的 awk 和 Perl 解决方案:我需要了解如何添加不重复其输出的附加字段,就像这些示例中的 "name" 一样。 即 devtwr1 在示例数据中只出现一次,如果我需要添加也只出现一次的其他字段,这是如何完成的? 抱歉,已广泛尝试但无法解决...

这是来源:

有一个文件:Ntab.txt是两台主机的示例文件,真实文件中有无数台主机一个接一个。

每个主机有多个 "displayName"s(地址),每个 'displayName'.

都有相应的数字
>cat Ntab.txt
name    devtwr1
displayName     00:67:BB
capacityInKB    104,857,600
consumedCapacityInKB    4,042,752
dpPoolID        20
displayName     00:7B:FD
capacityInKB    52,428,800
consumedCapacityInKB    14,880,768
dpPoolID        10
displayName     00:7C:28
capacityInKB    34,179,712
consumedCapacityInKB    29,804,544
dpPoolID        20
displayName     00:7C:29
capacityInKB    34,179,712
consumedCapacityInKB    5,462,016
dpPoolID        20
name    devtwr2
displayName     00:67:BB
capacityInKB    104,857,600
consumedCapacityInKB    4,042,752
dpPoolID        20
displayName     00:7B:FD
capacityInKB    52,428,800
consumedCapacityInKB    14,880,768
dpPoolID        10
displayName     00:7C:28
capacityInKB    34,179,712
consumedCapacityInKB    29,804,544
dpPoolID        20
displayName     00:7C:29
capacityInKB    34,179,712
consumedCapacityInKB    5,462,016
dpPoolID        20

我需要能够在每个 'name'(主机)之后将行中的 $2 数据生成为列,并且采用 csv 类型格式,标题可选。我不能使用 (,:) 作为分隔符,因为数据包含它们(制表符或 ;)。

喜欢:

name;displayName;capacityInKB;consumedCapacityInKB;dpPoolID        
devtwr1;00:67:BB;104,857,600;4,042,752;20
devtwr1;00:7B:FD;52,428,800;14,880,768;10
devtwr1;00:7C:28;34,179,712;29,804,544;20
devtwr1;00:7C:29;34,179,712;5,462,016;20
devtwr2;00:67:BB;104,857,600;4,042,752;20
devtwr1;00:7B:FD;52,428,800;14,880,768;10
devtwr1;00:7C:28;34,179,712;29,804,544;20
devtwr1;00:7C:29;34,179,712;5,462,016;20

这是一个 Awk 解决方案,但无法解决如何添加 "name" 等并非所有字段都有数据的附加字段。

$ awk '=="name"{name=}
     ~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"} 
    =="dpPoolID"{print name out";"; out=""}' tmp2.txt
devtwr1;00:67:BB;104,857,600;4,042,752;20
devtwr1;00:7B:FD;52,428,800;14,880,768;10
devtwr1;00:7C:28;34,179,712;29,804,544;20
devtwr1;00:7C:29;34,179,712;5,462,016;20
devtwr2;00:67:BB;104,857,600;4,042,752;20
devtwr2;00:7B:FD;52,428,800;14,880,768;10
devtwr2;00:7C:28;34,179,712;29,804,544;20
devtwr2;00:7C:29;34,179,712;5,462,016;20

这是一个 Perl 解决方案,但又一次无法解决如何添加其他字段的问题,例如 "name" 并不总是有数据的字段。

perl -lane '
BEGIN {
  @fields = qw(name displayName capacityInKB consumedCapacityInKB dpPoolID);
  print join ";", @fields;
}
if (/^(name|displayName)/ && $data{displayName}) {
  print join ";", @data{@fields};
  %data = ( name => $data{name} );
}
$data{$F[0]} = $F[1];
END {
  print join ";",@data{@fields};
}' tmp2.txt > Report.csv

希望提供足够的信息以加深理解。 提前致谢。

将此保存到 ntab.pl 文件,执行 chmod +x ntab.pl 和 运行 it: cat ntab.txt | ./ntab.pl

#!/usr/bin/perl
use strict;
use constant CSV_SEP=>';';
my ($name,%flds);
my @fl=qw(displayName capacityInKB consumedCapacityInKB dpPoolID);
sub csv4name {
 my ($name,$vals)=@_;
 return 0 unless $name and %$vals;
 print join("\n",map { my $i=$_; join(CSV_SEP,$name,map { $vals->{$_}[$i]||='' } @fl) } 0..$#{$vals->{'displayName'}})."\n";
}
while (my ($attr,$val)=split /\s+/,<>) {
 if ($attr eq 'name') {
  csv4name($name,\%flds);
  $name=$val;
  %flds=();
  next;
 }
 push $flds{$attr}||=[],$val;
}
csv4name($name,\%flds);

没有任何性能优化,但对于不是非常大的文件 (<3G),此脚本可以顺利运行。