我有一个像
这样的文件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
答案 0 :(得分:3)
您可以使用这样的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
以便在先前定义的序列中输出。
答案 1 :(得分:2)
我强烈建议您为每一行打印每个可能的字段,并在适当时提供“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为第4个arg分割()。您只需要这样做,因为您在:
中使用Int:value
,而其他每个名称 - 值对都使用=
Charge=value
。如果您对输出中的Int=value
或任何其他一致的分隔符感到满意,那么您将不需要保存分隔符,因此第四个arg不需要GNU awk来分割()。
请注意,上面不需要对字段名称进行硬编码,它只使用输入文件中的任何名称,采用2遍方法从第一遍的每一行读取所有名称,因此它知道所有可能的字段名称用于在第二遍中的每一行打印。
您还应该考虑将输出格式更改为表格,以便在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特定的第4个arg来保存分隔符字符串到split()。