【问题标题】:Using nested loops in bash to replace characters in a string with an array of words在 bash 中使用嵌套循环将字符串中的字符替换为单词数组
【发布时间】:2014-10-26 16:11:00
【问题描述】:

我最近一直在学习 Bash,但我在嵌套循环时遇到了麻烦。

这就是我得到的。

input='ATAATAATAATG'
CODONTABLE=(ATA I ATC I ATT I ATG M ACA T
            ACC T ACG T ACT T AAC N AAT N
            AAA K AAG K AGC S AGT S AGA R
            AGG R CTA L CTC L CTG L CTT L
            CCA P CCC P CCG P CCT P CAC H
            CAT H CAA Q CAG Q CGA R CGC R
            CGG R CGT R GTA V GTC V GTG V
            GTT V GCA A GCC A GCG A GCT A
            GAC D GAT D GAA E GAG E GGA G
            GGC G GGG G GGT G TCA S TCC S
            TCG S TCT S TTC F TTT F TTA L
            TTG L TAC Y TAT Y TAA _ TAG _
            TGC C TGT C TGA _ TGG W)


for ((i=0;i<${#input};i++)) ; do
  let w+=1
  for c in $input ; do
    for h in $CODONTABLE ; do
      if [ $(echo ${input:x:3})=$(echo $CODONTABLE[w]) ] ; then
      mod+=(${CODONTABLE[w]})
      let x+=1
      else
      let w+=1
      fi
    done
  done
done
echo $mod
echo $input

我从中得到的是……

ATAATAATAATG
I

看来至少 ATA 被正确地翻译成 I。 但是,我想要的是

**ATA**ATAATAATG -> I
A**TAA**TAATAATG -> _
AT**AAT**AATAATG -> N
ATA**ATA**ATAATG -> I

因此最终输出为I_NI_NI_NM,我稍后会使用它。

简而言之,我如何创建一个正确的重复循环来遍历我的输入,翻译每个可能的 3 个字符帧,并将其附加到另一个数组?

【问题讨论】:

    标签: arrays bash loops bioinformatics


    【解决方案1】:

    您的代码实际上存在很多问题。其中一些是纯逻辑错误;其他人是由于对各种 Bash 构造的作用的误解。 (虽然我猜一些纯粹的逻辑错误是由于对各种 Bash 构造的误解而导致的问题的反复试验尝试解决的问题。)所以作为一般建议,我建议编写和测试小片段,看看它们是如何工作的,并使用调试输出(像echo "i=$i w=$w c=$c h=$h" 这样的小语句,可以帮助您查看代码中发生了什么)。这将帮助您建立一个有效的程序。

    以下是一些具体问题。它们不是一个完整的列表。


    这个:

    for ((i=0;i<${#input};i++)) ; do
      let w+=1
      ...
    done
    

    会给w123、...12。但我认为您实际上希望w 采用值0369?为此,您应该写:

    for (( w = 0 ; w < ${#input} ; w += 3)) ; do
      ...
    done
    

    (如果我误解了 w 应该是什么,我深表歉意。它的名字不是很容易记忆,而且你似乎有几种不同的用法,所以很难确定。顺便说一句 - 我建议把为更好地命名变量付出了一些努力。它使代码so更容易理解和调试。)


    由于$input 不包含任何空格,因此:

      for c in $input ; do
        ...
      done
    

    等价于:

      c=$input
      ...
    

    (也许您希望 for c in $input 循环遍历 $input 的字符?但这不是那个符号的作用。)


    您似乎试图将CODONTABLE 视为一个关联数组,但您还没有把它写成一个。如果您使用的是支持关联数组的 Bash 版本,那么您应该使用真正的:

    declare -A CODONTABLE=([ATA]=I [ATC]=I [ATT]=I [ATG]=M [ACA]=T
                           [ACC]=T [ACG]=T [ACT]=T [AAC]=N [AAT]=N
                           [AAA]=K [AAG]=K [AGC]=S [AGT]=S [AGA]=R
                           [AGG]=R [CTA]=L [CTC]=L [CTG]=L [CTT]=L
                           [CCA]=P [CCC]=P [CCG]=P [CCT]=P [CAC]=H
                           [CAT]=H [CAA]=Q [CAG]=Q [CGA]=R [CGC]=R
                           [CGG]=R [CGT]=R [GTA]=V [GTC]=V [GTG]=V
                           [GTT]=V [GCA]=A [GCC]=A [GCG]=A [GCT]=A
                           [GAC]=D [GAT]=D [GAA]=E [GAG]=E [GGA]=G
                           [GGC]=G [GGG]=G [GGT]=G [TCA]=S [TCC]=S
                           [TCG]=S [TCT]=S [TTC]=F [TTT]=F [TTA]=L
                           [TTG]=L [TAC]=Y [TAT]=Y [TAA]=_ [TAG]=_
                           [TGC]=C [TGT]=C [TGA]=_ [TGG]=W)
    

    如果不是,那么您的常规数组方法很好,但您应该将该逻辑放入其自己的函数中,而不是尝试使用深度嵌套循环在 CODONTABLE 中找到正确的映射:

    function dna_codon_to_amino ($) {
      local dna_codon="$1"
      local i
      for (( i = 0 ; i < ${CODONTABLE[@]} ; i += 2 )) ; do
        if [[ "$dna_codon" = "${CODONTABLE[i]}" ]] ; then
          echo "${CODONTABLE[i+1]}"
          return
        fi
      done
    
      # whoops, didn't find anything. print a warning to standard error,
      # return the amino acid '@', and indicate non-success:
      echo "Warning: invalid DNA codon: '$dna_codon'" >&2
      echo '@'
      return 1
    }
    

    然后您可以通过编写如下内容来调用它:

    amino_codon="$(dna_codon_to_amino "$dna_codon")"
    

    【讨论】:

    • 哇!这样一个好建议的宝库。对你的帮助感到震惊。您对我的错误的假设是正确的,在仔细阅读了您的建议后,我发现了许多我以前误解的关于 bash 脚本的事情。
    【解决方案2】:

    ruakhanswer 有很多好处,但我认为没有说明如何一次遍历字符串 3 个字母。这段代码就是这样做的:

    #!/usr/bin/env bash-4.3
    
    declare -A CODONTABLE
    CODONTABLE=(
                [ATA]=I [ATC]=I [ATT]=I [ATG]=M [ACA]=T
                [ACC]=T [ACG]=T [ACT]=T [AAC]=N [AAT]=N
                [AAA]=K [AAG]=K [AGC]=S [AGT]=S [AGA]=R
                [AGG]=R [CTA]=L [CTC]=L [CTG]=L [CTT]=L
                [CCA]=P [CCC]=P [CCG]=P [CCT]=P [CAC]=H
                [CAT]=H [CAA]=Q [CAG]=Q [CGA]=R [CGC]=R
                [CGG]=R [CGT]=R [GTA]=V [GTC]=V [GTG]=V
                [GTT]=V [GCA]=A [GCC]=A [GCG]=A [GCT]=A
                [GAC]=D [GAT]=D [GAA]=E [GAG]=E [GGA]=G
                [GGC]=G [GGG]=G [GGT]=G [TCA]=S [TCC]=S
                [TCG]=S [TCT]=S [TTC]=F [TTT]=F [TTA]=L
                [TTG]=L [TAC]=Y [TAT]=Y [TAA]=_ [TAG]=_
                [TGC]=C [TGT]=C [TGA]=_ [TGG]=W
    )
    
    input='ATAATAATAATG'
    i=("AAAAACAAGAATACAACCACGACTAGAAGCAGGAGTATAATCATGATT"
       "CAACACCAGCATCCACCCCCGCCTCGACGCCGGCGTCTACTCCTGCTT"
       "GAAGACGAGGATGCAGCCGCGGCTGGAGGCGGGGGTGTAGTCGTGGTT"
       "TAATACTAGTATTCATCCTCGTCTTGATGCTGGTGTTTATTCTTGTTT"
      )
    
    for string in "$input" "${i[@]}" 
    do
        echo "$string"
        fmt=$(printf "  %%-%ds  %%3s  %%s\\\\n" ${#string})
        #echo "$fmt"
        output=""
        while [ ${#string} -ge 3 ]
        do
            codon=${string:0:3}
            output="$output${CODONTABLE[$codon]}"
            printf "$fmt" "$string" "$codon" "$output"
            string=${string#?}
        done
    done
    

    关键部分是关联数组和两个表达式:

    codon=${string:0:3}  # Extract 3 characters from offset 0 of string
    string=${string#?}   # Drop the first character from string
    

    输出的第一部分是:

    ATAATAATAATG
      ATAATAATAATG  ATA  I
      TAATAATAATG   TAA  I_
      AATAATAATG    AAT  I_N
      ATAATAATG     ATA  I_NI
      TAATAATG      TAA  I_NI_
      AATAATG       AAT  I_NI_N
      ATAATG        ATA  I_NI_NI
      TAATG         TAA  I_NI_NI_
      AATG          AAT  I_NI_NI_N
      ATG           ATG  I_NI_NI_NM
    

    【讨论】:

    • 这对我来说是一个非常有用的阐述,因为我可以实际看到程序的每个周期都在发生什么。我接受你和 Ruakh 的遮阳篷作为我的问题的解决方案,但我不能在两者上打勾。
    • 你不能同时接受。接受 Ruak 的;我的是派生的。
    猜你喜欢
    • 2021-09-30
    • 2016-04-20
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多