根据特定列将一行解构为两行

根据特定列将一行解构为两行

我有一个.tsv文件 ( batch_1.catalog.tags.tsv) 包含 1,965,056 行 14 列我想将其中一些分成两行

第一行:以大于号 (>) 开头,后跟 14 列中的 8 列
第二行:仅第 10 列

例如。

>column3(a number) column4(numbers and letters) column5(a number) column6(- or +) column11(0 or 1) column12(0 or 1) column13(0 or 1) column14(0 or 1)       
column10(string with As,Ts,Gs,Cs, and sometimes Ns)    

以下是文件第六行的示例.tsv,由第三列指定:

0   1   6   gi|586799556|ref|NW_006530744.1|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    0   0   0   0    

这就是我想要的:

>6 gi|586799556|ref|NW_006530744.1| 141 +  0 0 0 0        
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    

但是,我只想对 tsv 文件 (batch_1.catalog.tags.tsv) 中第三列编号与不同文本文件 (whitelist.txt) 中的数字匹配的行执行此操作。

在上面的示例中,whitelist.txt文件将包含数字 6,尽管还有 8000 多行具有不同的第三列数字(即 ID)。其中whitelist.txt包括最多 6 位数字。

我一直在尝试另一种方法。我得到了下面的代码,用于使用白名单从文件中提取第 10 列.tsv。然而,grep 持续了 10 个小时并没有做任何事情(空cat.fa文件)。

cat whitelist.txt | while read line; do zgrep "^0    1       $line   " batch_1.catalog.tags.tsv.gz; done | cut -f 3,10 | sed -E -e's/^([0-9]+)       ([ACGTN]+)$/>\1Z\2/' | tr "Z" "\n" > cat.fa    

下面使用 awk 或 perl 的两个解决方案都可以完美工作。尽管白名单中的 ID 不按顺序排列,但它们也会按顺序打印出来。 Perl 解决方案打印以制表符分隔的行,而 awk 则打印以空格分隔的行。

答案1

perl -F'\t+' -lane '
   @ARGV and $h{$F[0]}++,next;
   print ">", join("\t", @F[2..5,-4..-1]), $\, $F[9] if exists $h{$F[2]};
' whitelist.txt batch_1.catalog.tags.tsv

假设您的文件是制表符分隔的。

请注意,如果您的文件可能有 windows 或 mac 行结尾,那么谨慎的做法是首先通过实用程序 dos2unix 等将它们转换为 unix 行结尾(“\n”)。因为很多时候,我们发现提供的代码没有由于诸如此类的原因,在OP端工作。

工作原理

  • 请注意何时Perl处理第一个参数(在本例中为 ,whitelight.txt则 @ARGV 保存batch_1.catalog.tsv文件,即 @ARGV = 1 => @ARGV 在布尔上下文中被评估为 TRUE。
  • @ARGV and $h{$F[0]}++,next可以解释为:当我们处理白光文件时,然后将该$F[0]文件的第一个字段( )添加到哈希中%h,然后立即转到下一行。
  • 这些下面的任何行都将处理 TSV 文件,因为当时 @ARGV 不包含任何内容,因此计数为零。
  • 只有那些第三个字段$F[2]恰好是哈希中的键的 TSV 文件记录才应转到标准输出%h
  • 一旦决定打印 TSV 记录,则其打印格式为:(注意:OFS打印的默认格式为NULL
  • ">"$F[2]意味着第三个字段前面有一个>
  • 字段 4,5,6 =>@F[3..5]将按 TAB 分隔和连接。
  • 最后 4 个字段 =>@F[-4..-1]将按 TAB 分隔和连接。
  • 第 10 个字段$F[9]前面将有一个换行符,该换行符由$\==由于选项ORS而提供。\nPerl-l

答案2

awk解决方案:

假设来自文件的测试片段batch_1.catalog.tags.tsv

0   1   6   gi|586799556|ref|NW_006530744.1|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    0   0   0   0
1   2   7   hi|686711556|ref|NW_006530744.2|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   1   0   1
2   2   8   hi|686711556|ref|NW_006530744.2|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   1   1   1
3   3   9   th|776711556|ref|NW_006530744.2|    141 +   consensus   1   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   0   1   1

whitelight.txt以及文件中的测试片段:

6
7
9

命令:

awk 'NR==FNR{ a[$0]++; next }{ if ($3 in a) { 
     $0=">"$3 FS $4 FS $5 FS $6 FS $11 FS $12 FS $13 FS $14 RS $10; print}}' whitelist.txt batch_1.catalog.tags.tsv > cat.fa

最终cat.fa内容:

>6 gi|586799556|ref|NW_006530744.1| 141 + 0 0 0 0
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC
>7 hi|686711556|ref|NW_006530744.2| 141 + 1 1 0 1
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC
>9 th|776711556|ref|NW_006530744.2| 141 + 1 0 1 1
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC

细节

NR==FNR- 对第一个文件执行操作,即whitelight.txt

a[$0]++;- 从whitelight.txt文件中累积数字

if ($3 in a)- 如果第二个文件中的第三列值与任何累积数字匹配,则允许执行操作

RS- awk的记录分隔符,默认为换行符

相关内容