如何将不同的字符串添加到制表符分隔文件的单列中的重复项中以使其唯一

zer*_*mer 4 awk text-processing

我有一个 4 列制表符分隔的文件,最后一列有时有重复项。这是该文件的摘录:

chr7    116038644       116039744       GeneA
chr7    116030947       116032047       GeneA
chr7    115846040       115847140       GeneA
chr7    115824610       115825710       GeneA
chr7    115801509       115802609       GeneA
chr7    115994986       115996086       GeneA
chrX    143933024       143934124       GeneB
chrX    143933119       143934219       GeneB
chrY    143933129       143933229       GeneC
Run Code Online (Sandbox Code Playgroud)

对于该列中的每一组重复项,我想将它们转换为这样的(不真正触及该列中的非重复值):

chr7    116038644       116039744       GeneA-1
chr7    116030947       116032047       GeneA-2
chr7    115846040       115847140       GeneA-3
chr7    115824610       115825710       GeneA-4
chr7    115801509       115802609       GeneA-5
chr7    115994986       115996086       GeneA-6
chrX    143933024       143934124       GeneB-1
chrX    143933119       143934219       GeneB-2
chrY    143933129       143933229       GeneC
Run Code Online (Sandbox Code Playgroud)

我怎样才能用awkorsed或 Bash 的for循环来做到这一点?

Adm*_*Bee 7

尝试这个

awk -F'\t' -v OFS='\t' '{$4=$4 "-" (++count[$4])}1' file.tsv
Run Code Online (Sandbox Code Playgroud)

这将在计数器数组中存储第 4 个字段的每个值的出现count(其中第 4 个字段的值用作“索引”),并将该计数器的预递增值附加到第 4 个字段,由一个分隔短跑。

上面的“简单”示例有一个缺点:它会为第 4 列中仅在文件中出现一次的那些值添加一个消歧数字。为了抑制这种情况,以下双通道方法将起作用(命令通过两行分解\以提高可读性):

 awk -F'\t' -v OFS='\t' 'NR==FNR{f[$4]++}\
      NR>FNR{if (f[$4]>1) {$4=$4 "-" (++count[$4])}; print}' file.tsv file.tsv
Run Code Online (Sandbox Code Playgroud)

请注意,要处理的文件作为参数声明了两次,因此将被读取两次。

  • 第一次读取时(由 表示FNR,每个文件的行计数器,等于NR,全局行计数器),我们简单地计算第 4 列的每个不同值在文件中出现的频率,并将其存储在数组中f。
  • 第二次读取文件时,我们执行实际的文本处理,就像在“简单”方法中一样,并将出现计数器附加到第 4 列,但前提是在第一遍中找到的出现总数大于 1。

这种方法避免了缓冲整个文件,如果文件非常大,这可能是一个优势。处理时间当然更长,因为文件被读取了两次。

作为一般规则,很少需要使用 shell 循环进行文本处理,因为awk 例如可以以更有效的方式自行执行循环操作。

  • 这是正确的。正如您可能自己想象的那样,没有单程方法可以将消歧标记限制为仅实际出现多次的那些值。可以通过缓冲文件并最终执行打印操作来完成,但对于可能由于内存限制而失败的大文件...... (2认同)