gawk 到 awk 中的区间表达式

Interval expressions in gawk to awk

我希望这是一个简单的修复

我最初使用 gawk 编写了一个干净简单的脚本,我首先使用它是因为当我解决原始问题时,我发现了。我现在需要调整它以仅使用 awk。

样本file.fasta:

>gene1

>gene235
ATGCTTAGATTTACAATTCAGAAATTCCTGGTCTATTAACCCTCCTTCACTTTTCACTTTTCCCTAACCCTTCAAAATTTTATATCCAATCTTCTCACCCTCTACAATAATACATTTATTATCCTCTTACTTCAAAATTTTT

>gene335
ATGCTCCTTCTTAATCTAAACCTTCAAAATTTTCCCCCTCACATTTATCCATTATCACCTTCATTTCGGAATCCTTAACTAAATACAATCATCAACCATCTTTTAACATAACTTCTTCAAAATTTTACCAACTTACTATTGCTTCAAAATTTTTCAT

>gene406
ATGTACCACACACCCCCATCTTCCATTTTCCCTTTATTCTCCTCACCTCTACAATCCCCTTAATTCCTCTTCAAAATTTTTGGAGCCCTTAACTTTCAATAACTTCAAAATTTTTCACCATACCAATAATATCCCTCTTCAAAATTTTCCACACTCACCAAC


gawk '/[ACTG]{21,}GG/{print a; print}{a=[=10=]}' file.fasta >"species_precrispr".fasta

我知道 awk 的工作原理如下:

awk '/[ACTG]GG/{print a; print}{a=[=11=]}' file.fasta >"species_precrispr".fasta

因此罪魁祸首是 {21,} 的区间表达式

我想要它做的是搜索它以匹配包含我的 "GG" 匹配剩余至少 21 个核苷酸的每一行。

有人能帮忙吗?

编辑:

感谢所有帮助: 有各种有效的解决方案。要回复一些评论,请提供一个更基本的初始输出示例和所达到的预期效果...

awk 命令之前: 猫 file1.fasta

>gene1
ATGCCTTAACTTTCAATAACTGG 
>gene2
ATGGGTGCCTTAACTTTCAATAACTG
>gene3
ATGTCAAAATTTTTCATTTCAAT
>gene4
ATCCTTTTTTTTGGGTCAAAATTAAA
>gene5
ATGCCTTAACTTTCAATAACTTTTTAAAATTTTTGG

以下代码都产生了相同的期望输出:

原码

gawk '/[ACTG]{21,}GG/{print a; print}{a=[=13=]}' file1.fasta 

在原始 awk 版本中添加间隔函数的细微修改 >3.x.x

awk --re-interval'/[ACTG]{21,}GG/{print a; print}{a=[=14=]}' file1.fasta

允许修改 val 和正确的输出,未经测试但应该适用于较低版本的 awk

awk -v usr_count="21" '/gene/{id=[=15=];next} match([=15=],/.*GG/){val=substr([=15=],RSTART,RLENGTH-2);if(gsub(/[ACTG]/,"&",val)>= usr_count){print id ORS [=15=]};id=""}' file1.fasta

awk --re-interval '/^>/ && seq { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS} /^>/{name=[=15=]; seq=""; next} {seq = seq [=15=] } END { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS }' file1.fasta

期望的输出:仅抓取基因名称和匹配 GG 之前具有 21 个核苷酸的序列序列

>gene1
ATGCCTTAACTTTCAATAACTGG 
>gene5
ATGCCTTAACTTTCAATAACTTTTTAAAATTTTTGG

最后只是为了显示丢弃的行

>gene2
ATG-GG-TGCCTTAACTTTCAATAACTG # only 3 nt prior to any GG combo 
>gene3
ATGTCAAAATTTTTCATTTCAAT # No GG match found 
>gene4
ATCCTTTTTTTTGGGTCAAAATTAAA # only 14 nt prior to any GG combo 

希望这对其他人有帮助!

编辑: 根据 OP 评论,也需要打印基因 ID,然后尝试以下操作。

awk '
/gene/{
  id=[=10=]
  next
}
match([=10=],/.*GG/){
  val=substr([=10=],RSTART,RLENGTH-2)
  if(gsub(/[ACTG]/,"&",val)>=21){
    print id ORS [=10=]
  }
  id=""
}
' Input_file

或根据 OP 的要求,上述解决方案的单行形式:

awk '/gene/{id=[=11=];next} match([=11=],/.*GG/){val=substr([=11=],RSTART,RLENGTH-2);if(gsub(/[ACTG]/,"&",val)>=21){print id ORS [=11=]};id=""}' Input_file


您能否尝试仅使用显示的示例进行以下编写和测试。

awk '
match([=12=],/.*GG/){
  val=substr([=12=],RSTART,RLENGTH-2)
  if(gsub(/[ACTG]/,"&",val)>=21){
    print
  }
}
' Input_file

或更通用的方法,其中创建了一个变量,用户可以在其中提及用户希望匹配的值应该出现在 GG 之前。

awk -v usr_count="21" '
match([=13=],/.*GG/){
  val=substr([=13=],RSTART,RLENGTH-2)
  if(gsub(/[ACTG]/,"&",val)>=usr_count){
    print
  }
}
'  Input_file

解释:为以上添加详细解释。

awk '                                ##Starting awk program from here.
match([=14=],/.*GG/){                    ##Using Match function to match everything till GG in current line.
  val=substr([=14=],RSTART,RLENGTH-2)    ##Storing sub-string of current line from RSTART till RLENGTH-2 into variable val here.
  if(gsub(/[ACTG]/,"&",val)>=21){    ##Checking condition if global substitution of ACTG(with same value) is greater or equal to 21 then do following.
    print                            ##Printing current line then.
  }
}
' Input_file                         ##Mentioning Input_file name here.

GNU awk 从 3.0 版开始接受正则表达式中的区间表达式。但是,只有从 4.0 版开始,区间表达式才​​默认启用。如果你有 awk 3.x.x,你必须使用标志 --re-interval 来启用它们。

awk --re-interval '/a{3,6}/{print}' file

人们在使用 FASTA 文件和使用 awk 时经常会忽视一个问题。当您有多行序列时,您的 match 可能覆盖多行。为此,您需要先组合您的序列。

用 awk 处理 FASTA 文件的最简单方法是建立一个名为 name 的变量和一个名为 seq 的变量。每次阅读完整序列时,您都可以对其进行处理。请注意,为了获得最佳处理方式,序列应存储为连续字符串,并且不应包含任何换行符或空白符。用于处理 fasta 的通用 awk,如下所示:

awk '/^>/ && seq { **process_sequence_here** }
     /^>/{name=[=11=]; seq=""; next}
     {seq = seq [=11=] }
     END { **process_sequence_here** }' file.fasta

在当前案例中,您的序列处理如下所示:

awk '/^>/ && seq { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS}
     /^>/{name=[=12=]; seq=""; next}
     {seq = seq [=12=] }
     END { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS }' file.fasta

听起来你想要的是:

awk 'match([=10=],/[ACTG]+GG/) && RLENGTH>22{print a; print} {a=[=10=]}' file

但考虑到您提供的样本输入,这可能就是您所需要的全部内容:

awk 'match([=11=],/.*GG/) && RLENGTH>22{print a; print} {a=[=11=]}' file

它们都可以在任何 awk 中工作。

使用更新后的样本输入:

$ awk 'match([=12=],/.*GG/) && RLENGTH>22{print a; print} {a=[=12=]}' file
>gene1
ATGCCTTAACTTTCAATAACTGG
>gene5
ATGCCTTAACTTTCAATAACTTTTTAAAATTTTTGG