假设我有一个变量序列,它是一个字符串。
> sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
我想创建一个数组,比如 seq,其中每个元素都是初始序列的 3 个字符子字符串,所以类似于
echo $seq[1]
echo $seq[2]
echo $seq[n]
给出:
AAA
GCA
TAG
其中 n 是数组的最后一个元素。有人可以编写脚本来执行此操作吗?这是我想要做的 unix 和 C++ 代码的奇怪组合,但我需要它全部是 unix
sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
array_name=(seq) while($i+2<length(sequence)) {
seq[i]=substring(sequence,i,3) i=i+3 }
答案1
假设您在以下位置执行此操作bash
:
sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
for (( i = 0; i < ${#sequence}; i += 3 )); do
printf '%s\n' "${sequence:i:3}"
done
这会迭代序列的长度,一次三个碱基对。在每次迭代中,打印下一组三个碱基。
要将它们放入数组中,seq
而不是将它们打印出来:
sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
for (( i = 0; i < ${#sequence}; i += 3 )); do
seq+=( "${sequence:i:3}" )
done
这给了你数组seq
。各个数组元素可用作"${seq[0]}"
、"${seq[1]}"
等。
为了得到另外两个阅读框,更改循环,使其从 1 或 2 开始。
答案2
在 中bash
,使用循环和索引处理长字符串可以是非常速度很慢,作为替代方案,您可以使用read
字符串并构建一个数组:
sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
declare -a seq=( "" )
while read -n 3 -r triple ; do seq+=( "$triple" ); done <<< "$sequence"
declare -p seq
该数组是使用空字符串的索引 0 创建的,因此您的索引按照要求从 1 开始。
其工作方式是使用“ read -n 3
”一次读取三个字符到变量中triple
,将其添加到数组(+=
)中,使用<<<
重定向来呈现序列stdin
。read
处理输入不是 3 的倍数的情况。
(如上面的编码,这很适合读取不间断的字母序列——这不是通用的“分割”例程,因为它没有对空格、转义字符、nul 字节等进行特殊处理。如果你设置了,IFS=""
那么read
将在如果您需要从输入中删除空格,可以使用... <<< ${sequence// /}
.
这是更普遍问题的一个特例 在 Bash 中将字符串拆分为数组,其中您还可以阅读有关粗心程序员的所有令人兴奋的陷阱。 )
答案3
如果您的字符串不包含空格或换行符,您可以使用grep
分隔字符串并创建一个数组:
sequence="AAAGCATATGCTAGCCCGTATAGCGATACTAGCTATACGATATATATGATCAATGCCCGTATAG"
seq=( $(printf '%s' "$sequence" | grep -o ... ) )
或使用fold
代替grep
:
seq=( $(printf '%s' "$sequence" | fold -b3 ) )
与 相比grep
,这将使最后一个字符 ( G
) 也成为数组元素。
笔记:如果您的字符串包含*
,这在某些情况下可能会导致问题。例如,如果您在当前工作目录中seq=( AT* ATA ATG )
有以 开头的文件名,它将扩展为文件名。AT
您可以使用set -o noglob
它来防止通配符。
更好的选择: 使用 readarray
而不是seq=(...)
:
readarray seq < <(printf '%s' "$sequence" | fold -b3 )
(归功于@Kusalananda)