有没有一种方法可以使用变量来定义awk match()函数'match($ 0,/ r {0,var} /)'

时间:2019-08-16 09:28:33

标签: regex awk fasta

我正在处理文本文件,每个文件有数千条记录。每个记录由两行组成:以>开头的标头,然后是带有长字符串-AGTCNR的行。这两行记录完整。
这是一个简单文件的样子:

>ACML500-12|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_-2
----TAAGATTTTGACTTCTTCCCCCATCATCAAGAAGAATTGT-------NNNN
>ACRJP458-10|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_N
--------NNNTCCCTTTAATACTAGGAGCCCCTGACATAGCCTTTCCTAAATAAT-----
>ASILO303-17|Dip|gs-Par|sp-Par vid|subsp-NA|co
-----TAAGATTCTGATTACTCCCCCCCTCTCTAACTCTTCTTCTTCTATAGTAGATG
>ASILO326-17|Dip|gs-Goe|sp-Goe par|subsp-NA|c
TAAGATTTTGATTATTACCCCCTTCATTAACCAGGAACAGGATGA------
>CLT100-09|Lep|gs-Col|sp-Col elg|subsp-NA|co-Buru
AACATTATATTTGGAANNN-------GATCAGGAATAGTCGGAACTTCTCTGAA------
>PMANL2431-12|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_
----ATGCCTATTATAATTGGAGGATTTGGAAAACCTTTAATATT----CCGAAT
>STBOD057-09|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_N
ATCTAATATTGCACATAGAGGAACCTCNGTATTTTTTCTCTCCATCT------TTAG
>TBBUT582-11|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_N
-----CCCCCTCATTAACATTACTAAGTTGAAAATGGAGCAGGAACAGGATGA
>TBBUT583-11|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_N
TAAGATTTTGACTCATTAA--NNAGTNNNNNNNNNNNNNNNAATGGAGCAGGAACAGGATGA
>AFBTB001-09|Col|gs-NA|sp-NA|subsp-NA|co-Ethi|site-NA|lat_N
TAAGCTCCATCC-------------TAGAAAGAGGGG---------GGGTGA
>PMANL2431-12|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_
----ATGCCTATTAGGAAATTGATTAGTACCTTTAATATT----CCGAAT---
>AFBTB003-09|Col|gs-NA|sp-NA|subsp-NA|co-Ethi|site-NA|lat_N
TAAGATTTTGACTTCTGC------CATGAGAAAGA-------------AGGGTGA
>AFBTB002-09|Cole|gs-NA|sp-NA|subsp-NA|co-Ethi|site-NA|lat_N
-------TCTTCTGCTCAT-------GGGGCAGGAACAGGG----------TGA
>ACRJP458-10|Lep|gs-NA|sp-NA|subsp-NA|co-Buru|site-NA|lat_N
NNNNNNNNNNNTCCCTTTAATACTAGGAGCCCCTTTCCT----TAAATAAT-----

使用以下代码,我可以为每条记录搜索第二行(包含字符串),并提取记录,记录中的记录最大数量为-N或{使用n变量在行的开头{1}}个字符,使用$start_gaps变量在行的结尾,这是在线程here中完成的:

$end_gaps

现在,我需要为每个记录搜索在“不包括”第二行的开始或结束端子的区域中是否出现start_Ns=10 end_Ns=10 awk -v start_N=$start_Ns -v end_N=$end_Ns ' /^>/ { hdr=$0; next }; match($0,/^[-Nn]*/) && RLENGTH<=start_N && match($0,/[-Nn]*$/) && RLENGTH<=end_N { print hdr; print }' infile.aln > without_shortseqs.aln -N字符,筛选出超过特定最大数量n-N个字符的记录。下面的代码可以做到这一点,但我需要使用一个可以轻松重置的变量:

n

对于变量,我尝试了以下操作,但失败了:

start_Ns=10
end_Ns=10
awk -v start_N=10 -v end_N=10 ' /^>/ { 
hdr=$0; next }; match($0,/^[-Nn]*/) && RLENGTH<=start_N &&
match($0,/[-Nn]*$/) && RLENGTH<=end_N && match($0,/N{0,11}/) { 
print hdr; print }' infile.aln > without_shortseqs_mids.aln

预期结果:

awk -v start_N=10 -v mid_N=11 -v end_N=10 ' /^>/ { 
hdr=$0; next }; match($0,/^[-Nn]*/) && RLENGTH<=start_N &&
match($0,/N{0,mid_N}/) && match($0,/[-Nn]*$/) && RLENGTH<=end_N { 
print hdr; print }' infile.aln > without_shortseqs_mids.aln

3 个答案:

答案 0 :(得分:1)

我建议采用以下逻辑,以免使事情复杂化。

  1. 搜索开始部分,将其从字符串中删除
  2. 搜索结尾部分,将其从字符串中删除
  3. 搜索其余部分的中间部分:
awk -v start_N=10 -v mid_N=11 -v end_N=10 '
   /^>/{hdr=$0; next}
   { seq=$0 }
   match(seq,/^[-Nn]*/) && RLENGTH > start_N { next }
   { seq=substr(seq,RSTART+RLENGTH) }
   match(seq,/[-Nn]*$/) && RLENGTH > end_N { next }
   { seq=substr(seq,1,RSTART-1) }
   { while (match(seq,/[-Nn]+/)) { 
        if(RLENGTH>mid_N) next
        seq=substr(seq,RSTART+RLENGTH)
     }
   }
   { print hdr; print $0 }' file

另一种方法是使用带有字符重复的扩展正则表达式:

awk -v start_N=10 -v mid_N=11 -v end_N=10 '
   (FNR==1) { ere_start = "^[-Nn]{" start_N+1 ",}"
              ere_end = "[-Nn]{" mid_N+1 ",}$"
              ere_mid = "[^-Nn][-Nn]{" end_N+1 ",}[^-Nn]"
   /^>/{hdr=$0; next}
   { seq=$0 }
   match(seq,ere_start) { next }
   match(seq,ere_end) { next }
   match(seq,ere-mid) { next }
   { print hdr; print $0 }' file

答案 1 :(得分:0)

您可以将字符串用作match的第二个参数,然后Awk中的常规字符串插值运算符可以正常工作。

awk -v start_N=10 -v mid_N=11 -v end_N=10 ' /^>/ {
        hdr=$0; next }
    match($0,/^[-Nn]*/) && RLENGTH<=start_N &&
        match($0,"N{0," mid_N "}") &&
            match($0,/[-Nn]*$/) && RLENGTH<=end_N {
        print hdr; print }'

稍微说明一下,如果使用/regex/,则斜杠之间的文本将立即解释为正则表达式,但是如果使用"regex"或一段计算结果为字符串,首先处理常规的Awk字符串处理函数,然后才将所得的字符串解释为正则表达式。

答案 2 :(得分:0)

感谢您的提问。以我的拙见,您应该重新表述一下您的问题,并确保对该主题的所有潜在读者都100%明确目标。

关于在awk不允许使用变量的构造中包含变量,有一个标准技巧可以应用您将使用的任何脚本工具(例如sed或在perl中甚至更复杂的东西)或Python):通过破坏单引号构造来中断awk脚本,然后在其中插入由shell执行的变量扩展,而不是由awk 执行的扩展。例如,在这里,您将在Bash中定义mid_N,然后在awk脚本的中间使用"${mid_N}",紧接在其前的单引号和紧随其后的(重新)开放单引号。像这样:

mid_N=11
awk -v start_N=10 -v end_N=10 ' /^>/ { 
hdr=$0; next }; match($0,/^[-Nn]*/) && RLENGTH<=start_N &&
match($0,/N{0,'"${mid_N}"'}/) && match($0,/[-Nn]*$/) && RLENGTH<=end_N { 
print hdr; print }' infile.aln > without_shortseqs_mids.aln

这是针对您在“关于变量的情况下我尝试了以下操作但失败的方法”下面提到的特定问题的最小编辑解决方案: