在bash中使用嵌套循环用字符数组替换字符串中的字符

时间:2014-10-26 16:11:01

标签: arrays bash loops bioinformatics

我最近一直在接收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个字符帧,并将其附加到另一个数组?

2 个答案:

答案 0 :(得分:3)

您的代码实际上存在很多问题。其中一些是纯逻辑错误;其他人则是由于对各种Bash结构的误解。 (虽然我猜测一些纯粹的逻辑错误是由于试错法尝试修复因各种Bash结构的误解造成的问题。)所以作为一般性建议,我建议编写和测试小块,查看它们的工作方式,并使用调试输出(像echo "i=$i w=$w c=$c h=$h"这样的小语句可以帮助您查看代码中的内容)。这将有助于你建立一个工作计划。

以下是一些具体问题。它们不是完整的清单。


此:

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

会为w12,... 3提供12个值。但我认为您确实希望w采用值0369?为此,你应该写:

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

(如果我误解了w应该是什么,我道歉。它的名字不是很麻烦,你似乎用了几种不同的方式,所以很难顺便说一句 - 顺便说一句 - 我建议你更加努力地命名你的变量。它使代码所以更容易理解和调试。)


由于$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")"

答案 1 :(得分:1)

ruakh answer中有很多好处,但我认为没有解释如何一次翻阅字符串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