【问题标题】:Combine multiple grep variables in one column-wise file将多个 grep 变量合并到一个列式文件中
【发布时间】:2018-06-26 18:37:22
【问题描述】:

我有一些 grep 表达式来计算匹配字符串的行数,每个用于一组具有不同扩展名的文件:

Nreads_ini=$(grep -c '^>' $WDIR/*_R1.trim.contigs.fasta)
Nreads_align=$(grep -c '^>' $WDIR/*_R1.trim.contigs.good.unique.align)
Nreads_preclust=$(grep -c '^>' $WDIR/*_R1.trim.contigs.good.unique.filter.unique.precluster.fasta)
Nreads_final=$(grep -c '^>' $WDIR/*_R1.trim.contigs.good.unique.filter.unique.precluster.pick.fasta)

每个 grep 都会输出样本名称和出现次数,如下所示。

第一个:

PATH/V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT_R1.trim.contigs.fasta:13175
PATH/V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT_R1.trim.contigs.fasta:14801
PATH/V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT_R1.trim.contigs.fasta:13475
PATH/V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG_R1.trim.contigs.fasta:13424
PATH/V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA_R1.trim.contigs.fasta:12053

第二个:

PATH/V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT_R1.trim.contigs.good.unique.align:12589
PATH/V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT_R1.trim.contigs.good.unique.align:13934
PATH/V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT_R1.trim.contigs.good.unique.align:12981
PATH/V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG_R1.trim.contigs.good.unique.align:12896
PATH/V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA_R1.trim.contigs.good.unique.align:11617

等等。我需要创建一个 .txt 文件,将这些数字 grep 输出作为列,将样本名称作为键列。样本名称是文件名中“_R1”之前的部分(V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA、V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG...):

Sample                                   | Nreads_ini | Nreads_align  |
-----------------------------------------------------------------------
V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT  | 13175      | 12589         | 
V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT  | 14801      | 13934         | 
V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT  | 13475      | 12981         | 
V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG  | 13424      | 12896         |
V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA  | 12053      | 11617         |

有什么想法吗?我的问题还有其他更简单的解决方案吗? 谢谢!

【问题讨论】:

    标签: bash count grep


    【解决方案1】:

    在此答案中,变量名称缩短为 inialign

    首先,我们从 grep 的输出中提取样本名称和计数。由于我们必须多次这样做,我们定义了函数

    e() { sed -E 's,^.*/(.*)_R1.*:(.*)$,\1\t\2,'; }
    

    然后我们将提取的数据合并到一个文件中。具有相同样本名称的行将被合并。

    join -t $'\t' <(e <<< "$ini") <(e <<< "$align")
    

    现在我们几乎有了预期的输出。我们只需要为表格添加表头和画线。

    join ... | column -to " | " -N Sample,ini,align
    

    这将打印出来

    Sample                                  | ini   | align
    V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT | 13175 | 12589
    V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT | 14801 | 13934
    V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT | 13475 | 12981
    V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG | 13424 | 12896
    V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA | 12053 | 11617
    

    在标题后添加一条水平线作为练习供读者使用:)

    这种方法也适用于两个以上的数字列。 join-N 部分必须扩展。 join 只能处理两个文件,需要我们使用笨拙的解决方法...

    e() { sed -E 's,^.*/(.*)_R1.*:(.*)$,\1\t\2,'; }
    join -t $'\t' <(e <<< "$var1") <(e <<< "$var2") |
    join -t $'\t' - <(e <<< "$var3") | ... | join -t $'\t' - <(e <<< "$varN") |
    column -to " | " -N Sample,Col1,Col2,...,ColN
    

    ...所以添加另一个辅助函数会更容易

    e() { sed -E 's,^.*/(.*)_R1.*:(.*)$,\1\t\2,'; }
    j2() { join -t $'\t' <(e <<< "$1") <(e <<< "$2"); }
    j() { join -t $'\t' - <(e <<< "$1"); }
    j2 "$var1" "$var2" | j "$var3" | ... | j "$varN" |
    column -to " | " -N Sample,Col1,Col2,...,ColN
    

    或者,如果所有输入都包含相同顺序的相同样本,join 可以替换为单个 paste 命令。

    【讨论】:

    • 很好的解决方案!但是我应该怎么做才能根据其他 grep 表达式(preclust 和 final)添加更多列?似乎 join 只允许合并 2 个变量。
    • @ALG 哦,我忘了join 只能处理两个文件。但是,有一个解决方法,请参阅我更新的答案。我还简化了标头规范。
    【解决方案2】:

    假设您有包含要解析的数据的文件:

    $ cat file1
    PATH/V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT_R1.trim.contigs.fasta:13175
    PATH/V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT_R1.trim.contigs.fasta:14801
    PATH/V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT_R1.trim.contigs.fasta:13475
    PATH/V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG_R1.trim.contigs.fasta:13424
    PATH/V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA_R1.trim.contigs.fasta:12053
    $ cat file2
    PATH/V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT_R1.trim.contigs.good.unique.align:12589
    PATH/V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT_R1.trim.contigs.good.unique.align:13934
    PATH/V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT_R1.trim.contigs.good.unique.align:12981
    PATH/V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG_R1.trim.contigs.good.unique.align:12896
    PATH/V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA_R1.trim.contigs.good.unique.align:11617
    $ cat file3 # This is a copy of file2 but could be different
    PATH/V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT_R1.trim.contigs.good.unique.align:12589
    PATH/V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT_R1.trim.contigs.good.unique.align:13934
    PATH/V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT_R1.trim.contigs.good.unique.align:12981
    PATH/V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG_R1.trim.contigs.good.unique.align:12896
    PATH/V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA_R1.trim.contigs.good.unique.align:11617
    

    如果有 V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT 这样的键,你可以使用 awk:

    $ awk -F'[/.:]' '
        BEGINFILE{
          col[FILENAME]
        }
        { 
           row[$2]
           a[FILENAME,$2]=$NF
           next
        }
       END{
          for(i in row) { 
            printf "%s ",substr(i,1,length(i)-3)
            for(j in col) 
              printf "%s ",a[j SUBSEP i]; printf "\n" 
          }
      }' file1 file2 file3
    V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG 13424 12896 12896
    V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT 13175 12589 12589
    V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT 13475 12981 12981
    V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT 14801 13934 13934
    V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA 12053 11617 11617
    

    这个 awk 脚本填充了 3 个数组 colrowa,分别存储所有文件的列名(文件名)、行内容和值。

    END 语句通过循环遍历所有行和列来打印数组 a 的内容。

    如果你需要餐桌装饰,使用这个:

    { printf "Sample Nreads_ini Nreads_align Nreads_align \n"; awk -F'[/.:]' 'BEGINFILE{col[FILENAME]}{row[$2];a[FILENAME,$2]=$NF;next}END{for(i in row) { printf "%s ",substr(i,1,length(i)-3); for(j in col) printf "%s ",a[j SUBSEP i]; printf "\n" }}' file1 file2 file3; } | column -t  -s' ' -o ' | '
    

    【讨论】:

    • 问题是for循环。使用大量文件时它不起作用,这是我的情况。
    【解决方案3】:

    您能否尝试关注一下,如果这对您有帮助,请告诉我。

    awk --re-interval -F"[/.:]"  '
    BEGIN{
      print "Sample                                   | Nreads_ini | Nreads_align  |"
    }
    FNR==NR{
      match($2,/.*[A-Z]{10}/);
      array[substr($2,RSTART,RLENGTH)]=$NF;
      next
    }
    match($2,/.*[A-Z]{10}/) && (substr($2,RSTART,RLENGTH) in array){
      print substr($2,RSTART,RLENGTH),array[substr($2,RSTART,RLENGTH)],$NF
    }
    ' OFS=" | "  first_one  second_one | column -t
    

    输出如下。

    Sample                                   |  Nreads_ini  |  Nreads_align  |
    V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT  |  13175       |  12589
    V3_F357_N_V4_R805_1_A2_bach2_GAGTGATCGT  |  14801       |  13934
    V3_F357_N_V4_R805_1_A3_bach3_TGAGCGTGCT  |  13475       |  12981
    V3_F357_N_V4_R805_1_A4_bach4_TGTGTGCATG  |  13424       |  12896
    V3_F357_N_V4_R805_1_A5_bach5_TGTGCTCGCA  |  12053       |  11617
    

    【讨论】:

    • 似乎不起作用,它正在尝试读取名称为 PATH/V3_F357_N_V4_R805_1_A1_bach1_GTATCGTCGT_R1.trim.contigs.fasta:13175(文件名加上 grep 计数)的文件,该文件不存在。
    • @ALG,根据您显示的输出,它给了我相同的输出,让我现在将其发布在我的帖子中。
    • @ALG,看起来来自我的代码的输出与您显示的一样,请让我知道什么不起作用。
    • 也许我没有以正确的方式应用它。我采用了您发布的代码,并将 first_one 替换为 $Nreads_ini 并将 second_one 替换为 $Nreads_align。执行时,它给了我一个错误:awk: cmd. line:3: fatal: cannot open file (the one mentioned before)
    • @ALG,它无法找到文件是不言自明的。所以看起来你在 awk 代码中传递了 shell 变量,你能确保你的 shell 变量中有正确的值然后让我知道吗?
    猜你喜欢
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多