将匹配的行合并为一行

将匹配的行合并为一行

我被困在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()
}

从高层次来看,它的作用是:

  1. 在记忆中保留一行。 (不要打印。)
  2. 看下一行。如果字段 2 与保留线路的字段 2 匹配:
  3. 对于保留行的每个字段,如果该字段为空,则将其设置为当前查看的行中该字段的值。
  4. 转到2。
  5. 当下一行的字段2匹配保留的字段 2(即步骤 2 中的测试失败):
  6. 打印保留的行
  7. 将内存中保存的行替换为下一行(在上面 5 中发现不匹配的行)。
  8. 转到2。
  9. 当到达文件末尾时,打印保留的行。

上面代码逻辑的关键部分(实际合并行的部分)是:

hold[2] == $2 {
  for (i=4; i<=size; i++) {
    if (hold[i] == "") {
      hold[i] = $i
    }
  }
  next
}

这与我的高级描述的步骤 2 到步骤 4 一致。

相关内容