如果我有以下内容:
>ID_10_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
(即 fasta 文件!)
我希望能够根据位置(第一个元素的第二个元素,即 10)定位子字符串,并在其周围取 n 个位置,即 5 个位置
EFGHIJKLMNO
然后用第 1 行的第 4 个元素替换感兴趣的位置 - 即 X:
EFGHIXKLMNO
我可以找到子字符串,这很好...但是我在使用第 1 行的元素在第 2 行中进行替换时遇到了麻烦。我有以下代码:
#!/bin/bash
awk '
/>/{split($0,M,"_")}
!/^>/{split($1,N,"")
print M[1]"_"M[2]"_"M[3]"_"M[4]"\n"substr($1,M[2]-5,10)}
' $1
这让我得到了我的子字符串。
有人可以帮我解释一下我的逻辑来进行替换吗?我想我可以使用 sub() 函数并直接调用子字符串。我的想法是使用:
sub(regex/position,replacement,target)
在我的示例中将翻译为:
sub(N[2],N[4],substr($1,M[2]-5,10))
尝试这个结果
awk: cmd. line:5: print sub(M[2],M[4],substr($1,M[2]-10,20))}
awk: cmd. line:5: ^ sub third parameter is not a changeable object
所以看来我无法显式调用子字符串,而且我也怀疑是否能够在正则表达式参数中使用位置元素。
有人可以帮我编写代码以形成通用解决方案吗?我的输入是
>ID_10_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
所需的输出是:
EFGHIXKLMNO
我将在同一个文件中有许多输入。
还必须成立的是,虽然我正在寻找由第 1 行中给出的位置两侧的 5 个位置组成的子字符串,但如果第 1 行中的位置 < 5,则必须在指定位置进行替换即
>ID_2_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
AXCDEFG
如果最终的子字符串始终具有一定的长度,即如果我指定了 10 个子字符串,但替换位于上面的位置 2,则在替换完成后会选择 8 个字符,这会很好(但不是必需的)长度为10的子串
谢谢
最佳答案
这个 awk 脚本会产生您想要的输出:
awk -F_ '/^>/{p=$2;s=$NF;next}{print substr($0,p-5,5) s substr($0,p+1,5)}' file
第一个 block 保存您的位置p
和替换字符s
。第二个打印 p
之前的 5 个字符(替换字符),然后打印 p
之后的 5 个字符。
演示:
$ cat file
>ID_10_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
$ awk -F_ '/^>/{p=$2;s=$NF;next}{print substr($0,p-5,5) s substr($0,p+1,5)}' file
EFGHIXKLMNO
下面是代码的更新版本,用于处理距行首或行尾 5 个字符以内的位置。由于它稍长一些,为了清晰起见,我使用了脚本而不是单行文字。您可以像 awk -f script.awk file
一样运行它:
BEGIN { FS="_" }
/^>/ {
p=$2; c=$NF; next
}
{
if (p-5<1) s=1
else if (p+5>length($0)) s=length($0)-10
else s=p-5
print substr($0,s,p-s) c substr($0,p,11-p+s)
}
测试一下:
$ cat file
>ID_2_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
>ID_10_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
>ID_22_J_X
ABCDEFGHIJKLMNOPQRSTUVQXYZ
$ awk -f script.awk file
AXBCDEFGHIJK
EFGHIXJKLMNO
PQRSTUXVQXYZ
关于bash - awk sub() 按位置获取子字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29165703/