使用 shell 根据分隔符将多列拆分为行

使用 shell 根据分隔符将多列拆分为行

我有一个制表符分隔的文件,如下所示:

cg13201342  F   ARNT;ARNT;ARNT;CTSK 3'UTR;3'UTR;3'UTR;TSS1500
cg05269359  F   SCN4B;SCN4B;SCN4B;SCN4B 3'UTR;3'UTR;3'UTR;Body
cg06018296  R   NEK3;NEK3;NEK3;NEK3 3'UTR;3'UTR;3'UTR;Body
cg05172994  F   WDR20;WDR20;WDR20;WDR20 3'UTR;3'UTR;3'UTR;Body

期望的输出:

cg13201342  F   ARNT   3'UTR
cg13201342  F   ARNT   3'UTR
cg13201342  F   ARNT   3'UTR
cg13201342  F   CTSK   TSS1500
cg05269359  F   SCN4B  3'UTR
.
.

等等

我试过

awk 'BEGIN {
       FS = OFS = "\t"
     }
     {
       n = split($3, f, " *;*")
       for (i=1; i<=n; i++)
         print $1, f[i]
     }' probe-genes-regions >chk

但这只是分割第三列。我希望最后一列与第二列分开,并分别与第三列的第一个字段和最后一列的第一个字段形成行,依此类推

答案1

将字段 3 和 4 用分号拆分为单独的数组,然后对它们进行迭代,例如(假设字段 3 和 4 具有相同数量的元素):

解析.awk

BEGIN { OFS = "\t" }

{ 
  n = split($3, a, /;/); split($4, b, /;/)
  for(i=1; i<=n; i++)
    print $1, $2, a[i], b[i] 
}

像这样运行它:

awk -f parse.awk infile

输出:

cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       CTSK    TSS1500
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   Body
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    Body
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   Body

答案2

使用磨坊主( mlr):

sed 's/;/\t/' file | mlr --nidx --fs tab nest --evar ';' -f 4

首先使用制表sed符替换;每行的第一行,将第三个制表符分隔字段分成两个单独的字段。 GNU可以使用该命令sed插入制表符,但并非所有实现都可以。如果您不能,请输入文字制表符来代替按+ 。\tssed\tCtrl+VTab

然后,Miller 读取和写入制表符分隔数据 ( ),并根据第四个制表符分隔字段 ( ) 的分隔子字段--nidx --fs tab“分解”(或“取消嵌套”)每条记录。;nest --evar ';' -f 4

给出问题中的数据的输出:

cg13201342      F       ARNT    ARNT
cg13201342      F       ARNT    ARNT
cg13201342      F       ARNT    CTSK 3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    TSS1500
cg05269359      F       SCN4B   SCN4B
cg05269359      F       SCN4B   SCN4B
cg05269359      F       SCN4B   SCN4B 3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   Body
cg06018296      R       NEK3    NEK3
cg06018296      R       NEK3    NEK3
cg06018296      R       NEK3    NEK3 3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    Body
cg05172994      F       WDR20   WDR20
cg05172994      F       WDR20   WDR20
cg05172994      F       WDR20   WDR20 3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   Body

通过此操作uniq将删除相邻行的重复项。


仅使用awk

awk -F '\t' 'BEGIN { OFS=FS }
    {
        nf = split($3,a,";")
        for (i = 2; i <= nf; ++i) print $1, $2, a[1], a[i]
    }' file

这将第三场分割;,然后对于第三场的第二子场,继续输出前两个场以及原始第三场的第一个子场。

其输出与该答案顶部的管道的输出相同。

答案3

使用任何 POSIX awk,无论输入中的空格是什么:

$ awk -F'[[:space:];]+' -v OFS='\t' '{
    n=(NF-2)/2; for (i=1; i<=n; i++) print $1, $2, $(2+i), $(2+i+n)
}' file
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       CTSK    TSS1500
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   Body
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    Body
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   Body

相关内容