我被困在awk
命令中查找重复行并将其合并为一个
这是我的文件的外观(我没有标题),它已经在第 2 列上排序:
1, abc, 123, , , , , , , , , ,
2, xyz, 123, , , , , , , , , ,
3, pqr, 123, , , , , , , , , ,
4, pqr, 123, , ,10, ,12, , , , ,
5, pqr, 123, , , , , , , ,1,2,
6, def, 123, , , , , , , , , ,
7, lmn, 123, , , , , , , , , ,
8, lmn, 123, , ,22, ,11, , , , ,
9, tuv, 123, , , , , , , , , ,
10, qrs, 123, , , , , , , , , ,
输出将是:
1, abc, 123, , , , , , , , , ,
2, xyz, 123, , , , , , , , , ,
3, pqr, 123, , ,10, ,12, , ,1,2,
6, def, 123, , , , , , , , , ,
7, lmn, 123, , , 22, 11, , , , , ,
9, tuv, 123, , , , , , , , , ,
10, qrs, 123, , , , , , , , , ,
任何帮助表示赞赏。提前致谢
答案1
这可以用一行代码完成,但它足够棘手,值得一个完整的脚本:
#!/usr/bin/awk -f
# This shebang works on Mac; Linux boxes should use:
#!/bin/awk -f
BEGIN {
FS = ", *";
OFS = ", "
}
function printhold() {
for (i=1; i<size; i++) {
printf "%s", hold[i] OFS
}
print hold[size]
}
NR == 1 {
size = split ($0, hold, ", *")
next
}
hold[2] == $2 {
for (i=4; i<=size; i++) {
if (hold[i] == "") {
hold[i] = $i
}
}
next
}
{
printhold()
size = split ($0, hold, ", *")
}
END {
printhold()
}
从高层次来看,它的作用是:
- 在记忆中保留一行。 (不要打印。)
- 看下一行。如果字段 2 与保留线路的字段 2 匹配:
- 对于保留行的每个字段,如果该字段为空,则将其设置为当前查看的行中该字段的值。
- 转到2。
- 当下一行的字段2不匹配保留的字段 2(即步骤 2 中的测试失败):
- 打印保留的行
- 将内存中保存的行替换为下一行(在上面 5 中发现不匹配的行)。
- 转到2。
- 当到达文件末尾时,打印保留的行。
上面代码逻辑的关键部分(实际合并行的部分)是:
hold[2] == $2 {
for (i=4; i<=size; i++) {
if (hold[i] == "") {
hold[i] = $i
}
}
next
}
这与我的高级描述的步骤 2 到步骤 4 一致。