Text-Processing

合併特定列中的多行

  • April 21, 2022

我有一個這樣的文件:

xxx ax1 bx1
xxx ax2 bx2 cx2
xxx ax3 bx3
yyy ay1     cy1
zzz az1     cz1
zzz az1 bz2
...

我想要這樣的輸出:

xxx ax1,ax2,ax3 bx1,bx2,bx3 cx2
yyy ay1                     cy1
zzz az1         bz2         cz1
...

我嘗試使用 awk awk -F'\t' -v OFS='\t' '{x=$1;$1="";a[x]=a[x]$0}END{for(x in a)print x,a[x]}' file。但是這個命令忽略了它們所屬的列,輸出不是我想要的。

awk '
BEGIN{ FS=OFS="\t" }
    { for(i=2; i<=NF;i++)
      if (!seen[$1, $i, i]++)
          grp[$1, i]=(grp[$1, i]==""?"":grp[$1, i] ($i!=""?",":"")) $i
      else
          grp[$1, i]= grp[$1, i]
    }

END{ for(x in grp) {
        split(x, tmp, SUBSEP);
        join[tmp[1]]=(join[tmp[1]]==""?"":join[tmp[1]] OFS) grp[x]
    }
    for (x in join) print x, join[x]
}' infile

輸出:

yyy     ay1             cy1
xxx     ax1,ax2,ax3     bx1,bx2,bx3     cx2
zzz     az1     bz2     cz1

將欄位括在括號內以檢查其位置是否正確:

awk '
BEGIN{ FS=OFS="\t" }
    { for(i=2; i<=NF;i++)
      if (!seen[$1, $i, i]++)
          grp[$1, i]=(grp[$1, i]==""?"":grp[$1, i] ($i!=""?",":"")) $i
      else
          grp[$1, i]= grp[$1, i]
    }

END{ for(x in grp) {
        split(x, tmp, SUBSEP);
        join[tmp[1]]=(join[tmp[1]]==""?"":join[tmp[1]] OFS) "["grp[x]"]"
    }
    for (x in join) print x, join[x]
}' infile

輸出:

yyy     [ay1]   []      [cy1]
xxx     [ax1,ax2,ax3]   [bx1,bx2,bx3]   [cx2]
zzz     [az1]   [bz2]   [cz1]

筆記:

  • 無論您的輸入是否已排序,此答案都將起作用。
  • 這個答案將在輸出時打亂記錄。
  • 該程式碼!seen[$1, $i, i]++用於區分列中每個 Id 的條目。如果要刪除所有列中的重複條目而不考慮 ID,請將其更改為!seen[$1, $i]++);

例如:

$ cat infile
xxx     ax1     ax1
xxx     ax1     bx2     ax3
xxx     ax3     bx2
yyy     ay1     ay1     cy3
zzz     az1     bz3     cz1
zzz     az1     bz2     bz3

輸出(當!seen[$1, $i, i]++);重複的條目僅在屬於該 Id 的每一列中被刪除:

yyy     [ay1]   [ay1]   [cy3]
xxx     [ax1,ax3]       [ax1,bx2]       [ax3]
zzz     [az1]   [bz3,bz2]       [cz1,bz3]

輸出(當seen[$1, $i]++);無論該條目的列位置如何,都會刪除所有重複的條目:

yyy     [ay1]   []      [cy3]
xxx     [ax1]   [bx2]   [ax3]
zzz     [az1]   [bz3,bz2]       [cz1]

引用自:https://unix.stackexchange.com/questions/699861