查找字符串中三字符序列的频率

时间:2017-10-14 00:33:58

标签: linux bash unix

我在查找字符串中的三组字母时遇到问题。 我目前的代码是:

if [ -e  $1 ]
then
    echo File Exists
    grep -E -o -c \("[acgt][acgt][acgt]"\) $1
else
    echo File doesnt Exist
fi

如何显示字符串中发生事件的次数? 例如,我的字符串将包含

aacgtttgtaaccagaactgt
aac 3
tgt 2

3 个答案:

答案 0 :(得分:0)

您希望将{acgt}{acgt}{acgt}字符的每个三字符排列与aacgtttgtaaccagaactgt中的每个子字符串相匹配。 Bash可以非常简单地使用大括号扩展并使用字符串索引并检查测试字符串中的每个3字符子字符串,例如。

#!/bin/bash

str=aacgtttgtaaccagaactgt    ## string
len=${#str}                  ## length

while read -r pat; do        ## read each permutation from process substitution

    patlen=${#pat}           ## get the pattern length
    endex=$((len-patlen+1))  ## indexes to check (inclusive)
    declare -i ct=0          ## counter for matches

    ## check each character in $str
    for ((i = 0; i < endex; i++)); do
        ## test each $patlen substring against pattern, increment ct
        test "${str:$i:$patlen}" = "$pat" && ((ct++))
    done

    printf "%s  %d\n" "$pat" $ct  ## output results

done < <(printf "%s\n" {a,c,g,t}{a,c,g,t}{a,c,g,t})

注意:排列是由printf和大括号扩展

创建的
printf "%s\n" {a,c,g,t}{a,c,g,t}{a,c,g,t}

使用/输出

$ bash acgtpermcount.sh
aaa  0
aac  3
aag  0
aat  0
aca  0
acc  1
acg  1
act  1
aga  1
agc  0
agg  0
agt  0
ata  0
atc  0
atg  0
att  0
caa  0
cac  0
cag  1
cat  0
cca  1
ccc  0
ccg  0
cct  0
cga  0
cgc  0
cgg  0
cgt  1
cta  0
ctc  0
ctg  1
ctt  0
gaa  1
gac  0
gag  0
gat  0
gca  0
gcc  0
gcg  0
gct  0
gga  0
ggc  0
ggg  0
ggt  0
gta  1
gtc  0
gtg  0
gtt  1
taa  1
tac  0
tag  0
tat  0
tca  0
tcc  0
tcg  0
tct  0
tga  0
tgc  0
tgg  0
tgt  2
tta  0
ttc  0
ttg  1
ttt  1

仔细看看,如果您有其他问题,请告诉我。

注意:如果你有一个100,000,000字符的测试字符串,你可能需要一个比bash更快的工具来处理它。

答案 1 :(得分:0)

使用tailfoldgrepsortuniq

for i in {1..3}; do tail -c +"$i" infile; done | fold -w 3 | grep -Evx '.{,2}' |
    sort | uniq -c | sort -nr

导致

      3 aac
      2 tgt
      1 ttt
      1 ttg
      1 taa
      1 gtt
      1 gta
      1 gaa
      1 ctg
      1 cgt
      1 cca
      1 cag
      1 aga
      1 act
      1 acg
      1 acc

这是如何工作的:

  • tail -c +"$i" infile打印infile的内容,从对应于$i的偏移量开始,因此for循环的输出为

    aacgtttgtaaccagaactgt
    acgtttgtaaccagaactgt
    cgtttgtaaccagaactgt
    

其余的中间输出显示在末尾,从左到右编号的阶段对应于编号列表项:

  1. fold -w 3分别生成三个字符的行。
  2. grep -Evx '.{,2}'删除(-v)整行(-x)匹配两个或更少字符(.{,2})的行。 -E选项允许我们不要逃避大括号,但grep -vx '.\{,2\}'也可以正常工作。
  3. sort按字母顺序对输出进行排序(uniq需要排序输入)。
  4. uniq -c计算相同行的出现次数。
  5. sort -nr按出现次数排序,降序。

     1.      2.      3.              4.              5.
    ---------------------------------------------------
    aac     aac     aac           3 aac           3 aac
    gtt     gtt     aac           1 acc           2 tgt
    tgt     tgt     aac           1 acg           1 ttt
    aac     aac     acc           1 act           1 ttg
    cag     cag     acg           1 aga           1 taa
    aac     aac     act           1 cag           1 gtt
    tgt     tgt     aga           1 cca           1 gta
    acg     acg     cag           1 cgt           1 gaa
    ttt     ttt     cca           1 ctg           1 ctg
    gta     gta     cgt           1 gaa           1 cgt
    acc     acc     ctg           1 gta           1 cca
    aga     aga     gaa           1 gtt           1 cag
    act     act     gta           1 taa           1 aga
    gt      cgt     gtt           2 tgt           1 act
    cgt     ttg     taa           1 ttg           1 acg
    ttg     taa     tgt           1 ttt           1 acc
    taa     cca     tgt
    cca     gaa     ttg
    gaa     ctg     ttt
    ctg
    t
    

答案 2 :(得分:0)

这是一个更简单的解决方案。

#!/bin/bash
str='aacgtttgtaaccagaactgt'
for a in a c g t; do
    for e in a c g t; do
        for i in a c g t; do
            echo "${a}${e}${i} $(echo "$str" | grep -o "${a}${e}${i}" | wc -l)" | grep -vP '0$'
        done
    done
done