awk搜索然后将行转置为列

时间:2015-02-13 05:13:22

标签: search awk

对于awk和数据操作来说,这是一个很新的问题,但是已经陷入困境并且正在寻求帮助。

有一个文件: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




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

像:



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




希望有人可以提供帮助。

2 个答案:

答案 0 :(得分:0)

我相信这可以做你想要的:

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

如何运作

awk一次读取每一行。每行分为几个字段。第一个字段称为$1,第二个字段称为$2

  • $1=="name"{name=$2}

    这会捕获变量name中的名称。

  • $1~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"$2}

    当我们遇到displayNamecapacityInKBconsumedCapacityInKB的任何行时,请将其值附加到变量out

  • $1=="dpPoolID"{print name out";"$2; name=" "; out=""}

    当我们到达dpPoolID的行时,打印出收集的值。重置out以清空并将name设置为空格。

保留每行的名称

作为替代输出格式,我们可以保留名称并在每行显示:

$ awk '$1=="name"{name=$2} $1 ~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"$2} $1=="dpPoolID"{print name out";"$2; out=""}' Ntab.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

答案 1 :(得分:0)

您要求awk,如果适合您,则应接受John1024的解决方案。但这就是我想要用Perl来解决的问题。这是该语言的一种解决方案。它有一个小优势(IMO),因为它不依赖于每个记录中字段的特定顺序,除了displayName表示新集合的开始。

$ 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};
}' ntab.txt

输出:

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
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