[英]Sort columns of a file using Linux tools
我有一个像
ID=1234 PCharge=2 ext=5 IMSI=1234 Int:123 Charge=3
ID=1234 PCharge=2 ext=5 IMSI=1234 Charge=3
ID=1234 PCharge=2 ext=5 IMSI=1234 Int:4567 Charge=3
Charge=3 ID=1234 PCharge=2 ext=5 IMSI=1234
PCharge=2 ID=1234 Charge=3 ext=5 IMSI=1234
如何将该文件排序为类似的格式?
ID=1234 Charge=3 PCharge=2 ext=5 IMSI=1234
ID=1234 Charge=3 PCharge=2 ext=5 IMSI=1234
ID=1234 Charge=3 PCharge=2 ext=5 IMSI=1234
ID=1234 Charge=3 PCharge=2 ext=5 IMSI=1234
ID=1234 Charge=3 PCharge=2 ext=5 IMSI=1234 Int:123
ID=1234 Charge=3 PCharge=2 ext=5 IMSI=1234 Int:4567
您可以像这样使用awk脚本:
script.awk (已更新可选键和分隔符“:”和“ =“))
BEGIN { keys[1] = "ID"
keys[2] = "Charge"
keys[3] = "PCharge"
keys[4] = "ext"
keys[5] = "IMSI"
keys[6] = "Int"
}
NF>0 { delete values # reset each line due to optional keys
for( f =1 ; f <= NF; f++ ) {
split( $f, kv, "[=:]",seps) # split using RE separator and store individual separator in seps
values[ kv[1] ] = seps[1] kv[2] # prepend individual separator to value
}
tmp = ""
for(k = 1; k <= length(keys); k++ ) {
if( keys[k] in values) { # check due to optional keys
tmp=sprintf("%s%s%s%s",
tmp,
keys[k], values[keys[k]],
(k < NF) ? OFS : "" )
}
}
print tmp
}
运行它: awk -f script.awk yourfile
。
BEGIN
块设置输出场序列。 第二个块上的条件NF > 0
跳过空行。
第二个块遍历key=value
字段(awk在空格处将其拆分为字段)并存储键/值对。 在第二个循环中,将存储的对附加到tmp
,以按照先前定义的顺序输出。
我强烈建议您为每一行打印每个可能的字段,并在适当时提供“ N / A”值,因为这将使您的数据更容易在以下位置进行进一步处理:
$ cat tst.awk
BEGIN { OFS="," }
{
delete name2val
numFlds = split($0,flds,/[=:]|[[:space:]]+/,seps)
for (fldNr=1;fldNr<numFlds;fldNr+=2) {
name = flds[fldNr]
if ( !seen[name]++ ) {
names[++numNames] = name
}
name2sep[name] = seps[fldNr]
name2val[name] = flds[fldNr+1]
}
}
NR!=FNR {
for (nameNr=1;nameNr<=numNames;nameNr++) {
name = names[nameNr]
sep = name2sep[name]
val = (name in name2val ? name2val[name] : "N/A")
printf "%s%s%s%s", name, sep, val, (nameNr<numNames ? OFS: ORS)
}
}
$ awk -f tst.awk file file
ID=1234,PCharge=2,ext=5,IMSI=1234,Int:123,Charge=3
ID=1234,PCharge=2,ext=5,IMSI=1234,Int:N/A,Charge=3
ID=1234,PCharge=2,ext=5,IMSI=1234,Int:4567,Charge=3
ID=1234,PCharge=2,ext=5,IMSI=1234,Int:N/A,Charge=3
ID=1234,PCharge=2,ext=5,IMSI=1234,Int:N/A,Charge=3
上面的代码使用GNU awk作为split()的第四个参数。 您只需要这样做,因为您在Int:value
使用:
,而每个其他名称/值对在Charge=value
使用=
。 如果您对输出中的Int=value
或任何其他一致的分隔符感到满意,则无需保存分隔符,因此也不需要GNU awk来使第4个arg达到split()。
请注意,上面的代码不需要对字段名称进行硬编码,它只是使用输入文件中的任何名称,方法是采用两遍方法从第一遍读取每一行的所有名称,以便知道所有可能的方法字段名称用于第二遍的每一行打印。
您还应该考虑将输出格式更改为表格格式,以便可以在Excel中使用它,例如:
$ cat tst.awk
BEGIN { FS="[=:]|[[:space:]]+"; OFS="," }
{
delete name2val
for (fldNr=1;fldNr<NF;fldNr+=2) {
name = $fldNr
if ( !seen[name]++ ) {
names[++numNames] = name
}
name2val[name] = $(fldNr+1)
}
}
NR!=FNR {
if (FNR==1) {
for (nameNr=1;nameNr<=numNames;nameNr++) {
name = names[nameNr]
printf "%s%s", name, (nameNr<numNames ? OFS: ORS)
}
}
for (nameNr=1;nameNr<=numNames;nameNr++) {
name = names[nameNr]
val = (name in name2val ? name2val[name] : "N/A")
printf "%s%s", val, (nameNr<numNames ? OFS: ORS)
}
}
$ awk -f tst.awk file file
ID,PCharge,ext,IMSI,Int,Charge
1234,2,5,1234,123,3
1234,2,5,1234,N/A,3
1234,2,5,1234,4567,3
1234,2,5,1234,N/A,3
1234,2,5,1234,N/A,3
请注意,第二个脚本不需要GNU awk,它将在任何POSIX awk中工作,因为它不需要使用特定于gawk的第四个arg来保存分隔符字符串split()。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.