awk 搜索然后将行转置为列
awk search then transpose rows to columns
对 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
我需要能够在每个 'name'(主机)之后将行中的 $2 数据生成为列,并且采用 csv 类型格式,标题可选。我不能使用 (,:) 作为分隔符,因为数据包含它们(制表符或 ;)。
喜欢:
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
希望有人能提供帮助。
我相信这会满足您的要求:
$ awk '=="name"{name=} ~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"} =="dpPoolID"{print name out";"; 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
一次阅读每一行。每行被分成字段。第一个字段称为 </code>,第二个字段称为 <code>
.
=="name"{name=}
这会捕获变量 name
中的名称。
~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"}
当我们遇到 displayName
、capacityInKB
或 consumedCapacityInKB
的任何一行时,将其值附加到变量 out
.
=="dpPoolID"{print name out";"; name=" "; out=""}
当我们到达 dpPoolID
行时,打印出收集的值。将 out
重置为空并将 name
设置为 space.
保留每一行的名称
作为另一种输出格式,我们可以保留名称并将其显示在每一行中:
$ awk '=="name"{name=} ~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"} =="dpPoolID"{print name out";"; 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
您要求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
对 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
我需要能够在每个 'name'(主机)之后将行中的 $2 数据生成为列,并且采用 csv 类型格式,标题可选。我不能使用 (,:) 作为分隔符,因为数据包含它们(制表符或 ;)。
喜欢:
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
希望有人能提供帮助。
我相信这会满足您的要求:
$ awk '=="name"{name=} ~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"} =="dpPoolID"{print name out";"; 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
一次阅读每一行。每行被分成字段。第一个字段称为 </code>,第二个字段称为 <code>
.
=="name"{name=}
这会捕获变量
name
中的名称。~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"}
当我们遇到
displayName
、capacityInKB
或consumedCapacityInKB
的任何一行时,将其值附加到变量out
.=="dpPoolID"{print name out";"; name=" "; out=""}
当我们到达
dpPoolID
行时,打印出收集的值。将out
重置为空并将name
设置为 space.
保留每一行的名称
作为另一种输出格式,我们可以保留名称并将其显示在每一行中:
$ awk '=="name"{name=} ~/^(displayName|capacityInKB|consumedCapacityInKB)$/{out=out";"} =="dpPoolID"{print name out";"; 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
您要求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