我正在尝试使用从文件中提取一些数据grep
。
该文件是一个 DNA fasta 文件,包含以下行:
ATCGTAGCTAGCATCGTATCGATGCTGCTATGCTAGATGCTAGT
我需要找到TA
前面的所有 20 个字符TA
我目前正在尝试:grep -E -o ".{0,20}TA"
但这会产生输出,给出字符串之间的字符TA
- 在上面的行中给出 - 例如:
TCGATGCTGCTA
GCATCGTA
这是两次出现之间的字符串TA
,我想得到:
TAGCATCGTATCGATGCTGCTA
TCGTATCGATGCTGCTATGCTA
其中包含搜索字符串的实例。
有没有办法做到这一点grep
?
答案1
由于您想要重叠的字符串,恐怕默认情况下没有工具可以提供这一点。有必要循环输入以查找所有重叠的事件。下一个问题是正则表达式的贪婪本质:ATCGTA
如果ATCGTAGCTA
可以找到a,您将找不到前导。这使得循环变得更加复杂:
sed -E ':1
h;s/(.*TA).*/\1/
s/.{0,20}TA$/_&/
s/.*_//p
g;s/(.*)TA.*/\1/;t1
d
是我能想到的第一个解决方案。该示例的输出应包含您想要的所有序列:
GATGCTGCTATGCTAGATGCTA
TCGTATCGATGCTGCTATGCTA
TAGCATCGTATCGATGCTGCTA
ATCGTAGCTAGCATCGTA
ATCGTAGCTA
ATCGTA
解释:从上一场比赛开始似乎更容易,所以
h
将缓冲区保存在保持空间中以供下一个周期使用s/(.*TA).*/\1/
删除最后一个之后的所有内容TA
s/.{0,20}TA$/_&/
在您想要获取的序列的开头放置一个下划线作为标记s/.*_//p
删除标记之前的所有内容并打印序列- 为下一个周期做准备,
g
恢复保存的模式并s/(.*)TA.*/\1/
删除最后一个TA
和后续的,这样就不会再找到它 - 最后从找到序列的时候
t1
开始。:1
d
抑制最后的虚假输出
答案2
给定序列中只有 3 个子序列,其中 20 个碱基后跟TA
。这些都是相互重叠的。该grep
实用程序不能用于提取重叠的字符串,因为必须多次遍历线路才能找到所有子字符串。
ATCGTAGCTAGCATCGTATCGATGCTGCTATGCTAGATGCTAGT
----TA--TA------TA----------TA---TA-----TA--
01234567890123456789
01234567890123456789
01234567890123456789
这些序列可以通过以下脚本找到sed
(编写为与 一起使用sed -n
):
:again
s/\(.*.\{20\}TA\).*/\1/
h
s/.*\(.\{20\}TA\)/\1/p
g
s/TA$//
t again
- 第一个命令是标签 ,
again
我们将使用它来处理输入行中的下一个子序列。 - 第一个替换会删除最后一个之后的所有序列
TA
。 - 将
h
修剪后的序列放入“保留空间”(中的临时缓冲区sed
)。 - 第二次替换找到最后一个 20 个碱基序列,然后
TA
将其打印出来。 - 从保留空间中检索
g
先前存储的序列(丢弃刚刚打印的序列)。 - 第三次替换
TA
从字符串末尾删除了 。 - 如果最近的替换实际上做了任何事情,则该
t
命令会跳转到标签。again
测试它:
$ sed -n -f script.sed file
GATGCTGCTATGCTAGATGCTA
TCGTATCGATGCTGCTATGCTA
TAGCATCGTATCGATGCTGCTA
如果将单个sed
命令添加=
到脚本的最顶部sed
,您还将获得有关哪个输入行产生什么输出的指示。下面显示了数据在三行中重复:
$ sed -n -f script.sed file
1
GATGCTGCTATGCTAGATGCTA
TCGTATCGATGCTGCTATGCTA
TAGCATCGTATCGATGCTGCTA
2
GATGCTGCTATGCTAGATGCTA
TCGTATCGATGCTGCTATGCTA
TAGCATCGTATCGATGCTGCTA
3
GATGCTGCTATGCTAGATGCTA
TCGTATCGATGCTGCTATGCTA
TAGCATCGTATCGATGCTGCTA
答案3
也许有一种方法可以获得重叠匹配grep -o
(我不知道任何,甚至不知道grep -Po
),但同时你可以使用awk
:
echo ATCGTAGCTAGCATCGTATCGATGCTGCTATGCTAGATGCTAGT |
awk '{
i=0; for(s=$0; j = index(s,"TA"); s = substr($0, i + 1))
print ((i += j) > 20) ? substr($0, i - 20, 22) : substr($0, 1, i+1)
}'
ATCGTA
ATCGTAGCTA
ATCGTAGCTAGCATCGTA
TAGCATCGTATCGATGCTGCTA
TCGTATCGATGCTGCTATGCTA
GATGCTGCTATGCTAGATGCTA
如果您不希望从字符串开头开始进行较短的匹配,请将其简化为:
echo ATCGTAGCTAGCATCGTATCGATGCTGCTATGCTAGATGCTAGT |
awk '{
i=0; for(s=$0; j = index(s,"TA"); s = substr($0, i + 1))
if((i += j) > 20) print substr($0, i - 20, 22)
}'
TAGCATCGTATCGATGCTGCTA
TCGTATCGATGCTGCTATGCTA
GATGCTGCTATGCTAGATGCTA
同样的事情在perl
:
echo ATCGTAGCTAGCATCGTATCGATGCTGCTATGCTAGATGCTAGT |
perl -nle 'print $-[0] > 20 ? substr $_, $-[0]-20, 22 : substr $_, 0, $+[0] while /TA/g'
ATCGTA
ATCGTAGCTA
ATCGTAGCTAGCATCGTA
TAGCATCGTATCGATGCTGCTA
TCGTATCGATGCTGCTATGCTA
GATGCTGCTATGCTAGATGCTA
echo ATCGTAGCTAGCATCGTATCGATGCTGCTATGCTAGATGCTAGT |
perl -nle 'pos() -= 21, print $1 while /(.{20}TA)/g'
TAGCATCGTATCGATGCTGCTA
TCGTATCGATGCTGCTATGCTA
GATGCTGCTATGCTAGATGCTA
如果使用mawk
(类似 debian 的默认值),该awk
版本会更快。
虽然可以很好地展示sed
熟练程度,但任何sed
解决方案都必然有很多数量级比perl
或慢awk
。