使用join

使用join

我有多个文件,SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab SRR3384744.Gene.out.tab还有更多按此顺序排列的文件。我从这些文件中提取第一列和第四列并将其存储在输出文件中。我试图确保当我的脚本读取新文件时,它应该以选项​​卡分隔的方式提取数据,而不是将数据附加在每个文件的末尾。

输入文件:

SRR3384742.Gene.out.tab

N_unmapped      313860  313860  313860
N_multimapping  5786679 5786679 5786679
N_noFeature     286816  31696770        438410
N_ambiguous     1283487 32117   65902
AT1G01010       301     0       301
AT1G01020       623     1       622
AT1G03987       5       5       0
AT1G01030       151     2       149

SRR3384743.Gene.out.tab

N_unmapped      780346  780346  780346
N_multimapping  4621162 4621162 4621162
N_noFeature     182428  28470016        362650
N_ambiguous     1451612 43059   117293
AT1G01010       154     3       151
AT1G01020       685     2       683
AT1G03987       0       0       0
AT1G01030       63      0       63

我得到的输出:

SRR3384742.Gene.out.tab 
AT1G01010       301
AT1G01020       622
AT1G03987       0
AT1G01030       149
SRR3384743.Gene.out.tab 
AT1G01010       151
AT1G01020       683
AT1G03987       0
AT1G01030       63

所需输出:

SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab 
AT1G01010       301     151
AT1G01020       622     683
AT1G03987       0       0
AT1G01030       149     63

我尝试了以下脚本:

for sample in *Gene.out.tab; do echo -en $sample "\n"; awk 'NR>4 {print $1 "\t" $4}' $sample; awk '{print $0, $sample}' OFS='\t' $sample; done > output

答案1

这应该使用 GNU 为您提供注释中描述的输出awk

gawk 'FNR==1{names[c++]=FILENAME}
      FNR>4{ lines[$1] = "x"lines[$1] ? lines[$1]"\t"$4 : $4; } 
      END{ 
            for(i=0;i<=c;i++){
                printf "\t%s",names[i]
            } 
            printf "\n"; 
            for(i in lines){ 
                print i,lines[i]
            }
        }' *Gene.out.tab
    SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab
AT1G01010   301 151
AT1G01020   622 683
AT1G01030   149 63
AT1G03987   0   0

并且,为了使所有内容在视觉上也很好地对齐,请将其传递column

$ gawk 'FNR==1{names[c++]=FILENAME}FNR>4{ lines[$1] = "x"lines[$1] ? lines[$1]"\t"$4 : $4; } END{ for(i=0;i<=c;i++){printf "\t%s",names[i];} printf "\n"; for(i in lines){ print i,lines[i]}}' *Gene.out.tab | column -s$'\t' -t
            SRR3384742.Gene.out.tab  SRR3384743.Gene.out.tab
AT1G01010   301                      151
AT1G01020   622                      683
AT1G01030   149                      63
AT1G03987   0                        0

FNR是一个特殊的 awk 变量,它始终保存当前正在处理的文件的行号。FILENAME是一个 GNUawk特殊变量,保存当前正在处理的文件的名称。

  • FNR==1{names[c++]=FILENAME}:如果这是一个输入文件的第一行,则使用该变量作为其值为文件名的数组的c索引,并增加其值 yb 1 ( )。处理完所有文件后,将是第一个文件名,将是第二个文件名,依此类推。namesc++files[0]files[1]

  • FNR>4{ lines[$1] = "x"lines[$1] ? lines[$1]"\t"$4 : $4; }:这相当于:

    if(FNR>4){ 
          if("x"lines[$1]){
           lines[$1]"\t"$4
          else{
              lines[$1] = $4
          }
      }
    

    如果当前输入文件的行号为 5 或更多,请检查第一个字段在数组中是否有关联值lines。我们检查使用,"x"lines[$i]因为如果lines[$1]0,那么测试将为假,但x0为真,因此可以x防止这种情况。因此,如果我们确实有一个值,我们会向其附加一个制表符和当前行的第二个字段,如果我们没有值,我们会将其设置为当前行的第四个字段。

  • END{ ... }:处理完所有输入后执行此操作。

  • for(i=0;i<=c;i++){printf "\t%s",names[i]}; printf "\n";:打印names数组中的每个文件名,前面带有制表符。我们希望前导选项卡能够确保标题行和内容中的字段数量相同。打印文件名后,打印换行符。

  • for(i in lines){print i,lines[i]}:对于数组的每个索引lines,打印索引(ID),然后打印第一步中存储的关联值。

局限性:这需要将所有输出数据存储在内存中。在现代机器上这确实不应该成为问题,因为我们只存储 ID,每个文件每个 ID 只存储一个值,因此它应该能够在一台相当不错的机器上阻塞之前处理大量输入,但它可能会成为一个问题。确实存在大量数据的问题。

答案2

使用join

join -o '1.1 1.4 2.4' SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab
N_unmapped 313860 780346
N_multimapping 5786679 4621162
N_noFeature 438410 362650
N_ambiguous 65902 117293
AT1G01010 301 151
AT1G01020 622 683
AT1G03987 0 0
AT1G01030 149 63

使用paste

我想paste这就是您正在寻找的:

paste <(cut -f 1,4 SRR3384742.Gene.out.tab) <(cut -f4 SRR3384743.Gene.out.tab)
N_unmapped      313860  780346
N_multimapping  5786679 4621162
N_noFeature     438410  362650
N_ambiguous     65902   117293
AT1G01010       301     151
AT1G01020       622     683
AT1G03987       0       0
AT1G01030       149     63

该解决方案假设所有内容都*.tab应该具有:

  1. 相同的行数。
  2. 相同的顺序。

这是一个打印标题并处理多个文件的脚本:

#!/bin/bash
set -euo pipefail
echo $(printf '%s\t' "$@")
first_file=$1
shift
fifos="<(cut -f1,4 $first_file) "$(printf '<(cut -f4 %s) ' "$@")
eval "paste $fifos"
command *.out.tab
SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab
N_unmapped      313860  780346
N_multimapping  5786679 4621162
N_noFeature     438410  362650
N_ambiguous     65902   117293
AT1G01010       301     151
AT1G01020       622     683
AT1G03987       0       0
AT1G01030       149     63

答案3

for i in *.tab; do echo $i >/tmp/"$i"_out.txt ; awk '/^AT/{print $1,$4}' $i >> /tmp/"$i"_out.txt ; done
paste /tmp/*_out.txt| awk '{$3="";print }'

输出

SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab 
AT1G01010 301  151
AT1G01020 622  683
AT1G03987 0  0
AT1G01030 149  63

相关内容