计算UNIX中沿着一列到文件中的字符串中不同出现次数

时间:2018-04-17 14:15:21

标签: bash unix awk substr

我想计算一些标签文件中第二列中出现的不同字符串的次数。所以,通过这种方式我进行拆分以分离每个子串,然后尝试计算它们。但是无法正常工作。

输入就像

rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA AA

所需的输出

rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA   AA=9;AC=2
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA CC   AA=10;CC=1

依旧......

awk 'BEGIN {FS=OFS="\t"} {gf=split($2,gfp," ")} {for (i=1;i<=gf;i++){
                                      if (gfp[i]=="AA"){i++; printf $1FS$2FS"%s\n" i, gfp[i]}
                                      else if (gfp[i]=="AC" || gfp[i] == "CA"){i++; printf $1FS$2FS"%s"gfp[i]"="i";\n"}
                                                            }}' input > output

并且我也尝试做其他脚本,但我认为计算重复每个计数的次数与每行的次数相同。在这里,我在第一次拆分下执行了拆分,以便在子串之间识别

awk 'BEGIN {FS=OFS="\t"} {gf=split($2,gfp," ");} {for (i=1;i<=gf;i++){

                     par=gfp[i];
                     gfeach=split($2,gfpeach,par);
                     print par "=" gfeach[i]";"
                                              }
                      }' input > output

我确定有一些更简单的方法可以做到,但我无法完全解决。是否可以在UNIX环境中执行?提前致谢

4 个答案:

答案 0 :(得分:3)

您的输入与您的输出不匹配,因此我们只是猜测,但这可能是您想要的:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{
    delete cnt
    split($2,tmp,/ /)
    for (i in tmp) {
        str = tmp[i]
        cnt[str]++
    }

    printf "%s", $0
    sep = OFS
    for (str in cnt) {
        printf "%s%s=%d", sep, str, cnt[str]
        sep = ";"
    }
    print ""
}

根据您的输入真实情况,上面将输出以下内容:

$ cat file
rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA AA

$ awk -f tst.awk file
rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA        AA=9;AC=2
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA AA        AA=11

$ cat file
rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA CC

$ awk -f tst.awk file
rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA        AA=9;AC=2
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA CC        AA=10;CC=1

答案 1 :(得分:2)

这样的事情?

$ awk '{for(i=4;i<=NF;i++) c[$i]++; 
        for(k in c) {s=s sep k"="c[k]; sep=";"; c[k]=0} 
        $NF=$NF OFS s; s=sep=""}1' file | column -t

rs12255619  A/C  chr10  AA  AA  AC  AA  AA  AA  AA  AA  AA  AC  AA  AA=9;AC=2
rs7909677   A/G  chr10  AA  AA  AA  AA  AA  AA  AA  AA  AA  AA  AA  AA=11;AC=0

请注意,捕获的字母会逐渐增加,因为只会打印到一行的观察到的关键字。例如,如果第二行中有CC,则计数不会列在第一行。

答案 2 :(得分:2)

可以在perl

中完成
perl -lpe '$a{$_}++ for /\b[A-Z]{2}\b/g;
           $_.=" ".join(";",map{"$_=$a{$_}"}keys%a);
           %a = map{$_=>0}keys%a' file

产生

rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA AA=9;AC=2
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA CC AA=10;CC=1;AC=0

对于新要求

perl -lpe '$a{$_}++ for /\b[A-Z]{2}\b/g;
           $_.=" ".join(";",map{"$_=$a{$_}"}keys%a);
           undef %a' file

产生

rs12255619 A/C chr10    AA AA AC AA AA AA AA AA AA AC AA AC=2;AA=9
rs7909677 A/G chr10     AA AA AA AA AA AA AA AA AA AA CC CC=1;AA=10

答案 3 :(得分:-1)

#!/bin/bash

strings="AA AC CC"

while read line; do
        echo -n "$line: "
        for name in $strings; do
                num=$(echo $line | xargs -n1 | grep -cw $name)
                if [[ $num -ne 0 ]]; then
                        echo -n "$name=$num;"
                fi
        done
        echo
done < inputFile.txt