有没有办法在 awk match() 函数 'match([=10=],/r{0,var}/)' 中使用变量来定义范围
Is there a way to use a variable in to define range in awk match() function 'match($0,/r{0,var}/)'
我正在处理每个文件有数千条记录的文本文件。每条记录由两行组成:以 >
开头的 header 和后跟一长串字符的行 -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
字符在行首使用 $start_gaps
变量和行尾使用 $end_gaps
变量,这是在线程 :
中完成的
start_Ns=10
end_Ns=10
awk -v start_N=$start_Ns -v end_N=$end_Ns ' /^>/ {
hdr=[=12=]; next }; match([=12=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=12=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }' infile.aln > without_shortseqs.aln
现在我需要搜索 -
或 N
或 n
字符出现在区域 "not including" 第二行的开始或结束终端每条记录并过滤掉超过特定最大字符数 -
或 N
或 n
字符的记录。下面的代码可以做到,但我需要使用一个可以轻松重置的变量:
start_Ns=10
end_Ns=10
awk -v start_N=10 -v end_N=10 ' /^>/ {
hdr=[=13=]; next }; match([=13=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=13=],/[-Nn]*$/) && RLENGTH<=end_N && match([=13=],/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=[=14=]; next }; match([=14=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=14=],/N{0,mid_N}/) && match([=14=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }' infile.aln > without_shortseqs_mids.aln
预期结果:
>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
>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
您可以使用字符串作为 match
的第二个参数,然后 Awk 中的常规字符串插值运算符可以正常工作。
awk -v start_N=10 -v mid_N=11 -v end_N=10 ' /^>/ {
hdr=[=10=]; next }
match([=10=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=10=],"N{0," mid_N "}") &&
match([=10=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }'
稍微说明一下,如果您使用 /regex/
,那么斜杠之间的文本会立即被解释为正则表达式,但是如果您使用 "regex"
或一段代码求值为字符串,则首先处理常规 Awk 字符串处理函数,然后才将结果字符串解释为正则表达式。
为了不使事情过于复杂,我建议采用以下逻辑。
- 搜索开头部分,将其从字符串中删除
- 搜索结束部分,将其从字符串中删除
- 在余数中搜索中间部分:
awk -v start_N=10 -v mid_N=11 -v end_N=10 '
/^>/{hdr=[=10=]; next}
{ seq=[=10=] }
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 [=10=] }' 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=[=11=]; next}
{ seq=[=11=] }
match(seq,ere_start) { next }
match(seq,ere_end) { next }
match(seq,ere-mid) { next }
{ print hdr; print [=11=] }' file
感谢您的提问。以我的拙见,你应该稍微改一下你的问题,并确保你的 objective 对这个线程的所有潜在读者来说都是 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=[=10=]; next }; match([=10=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=10=],/N{0,'"${mid_N}"'}/) && match([=10=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }' infile.aln > without_shortseqs_mids.aln
这是针对您在 "As for a variable i tried the following but failed:"
下方提到的特定问题的最小编辑解决方案
我正在处理每个文件有数千条记录的文本文件。每条记录由两行组成:以 >
开头的 header 和后跟一长串字符的行 -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
字符在行首使用 $start_gaps
变量和行尾使用 $end_gaps
变量,这是在线程
start_Ns=10
end_Ns=10
awk -v start_N=$start_Ns -v end_N=$end_Ns ' /^>/ {
hdr=[=12=]; next }; match([=12=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=12=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }' infile.aln > without_shortseqs.aln
现在我需要搜索 -
或 N
或 n
字符出现在区域 "not including" 第二行的开始或结束终端每条记录并过滤掉超过特定最大字符数 -
或 N
或 n
字符的记录。下面的代码可以做到,但我需要使用一个可以轻松重置的变量:
start_Ns=10
end_Ns=10
awk -v start_N=10 -v end_N=10 ' /^>/ {
hdr=[=13=]; next }; match([=13=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=13=],/[-Nn]*$/) && RLENGTH<=end_N && match([=13=],/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=[=14=]; next }; match([=14=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=14=],/N{0,mid_N}/) && match([=14=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }' infile.aln > without_shortseqs_mids.aln
预期结果:
>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
>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
您可以使用字符串作为 match
的第二个参数,然后 Awk 中的常规字符串插值运算符可以正常工作。
awk -v start_N=10 -v mid_N=11 -v end_N=10 ' /^>/ {
hdr=[=10=]; next }
match([=10=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=10=],"N{0," mid_N "}") &&
match([=10=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }'
稍微说明一下,如果您使用 /regex/
,那么斜杠之间的文本会立即被解释为正则表达式,但是如果您使用 "regex"
或一段代码求值为字符串,则首先处理常规 Awk 字符串处理函数,然后才将结果字符串解释为正则表达式。
为了不使事情过于复杂,我建议采用以下逻辑。
- 搜索开头部分,将其从字符串中删除
- 搜索结束部分,将其从字符串中删除
- 在余数中搜索中间部分:
awk -v start_N=10 -v mid_N=11 -v end_N=10 '
/^>/{hdr=[=10=]; next}
{ seq=[=10=] }
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 [=10=] }' 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=[=11=]; next}
{ seq=[=11=] }
match(seq,ere_start) { next }
match(seq,ere_end) { next }
match(seq,ere-mid) { next }
{ print hdr; print [=11=] }' file
感谢您的提问。以我的拙见,你应该稍微改一下你的问题,并确保你的 objective 对这个线程的所有潜在读者来说都是 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=[=10=]; next }; match([=10=],/^[-Nn]*/) && RLENGTH<=start_N &&
match([=10=],/N{0,'"${mid_N}"'}/) && match([=10=],/[-Nn]*$/) && RLENGTH<=end_N {
print hdr; print }' infile.aln > without_shortseqs_mids.aln
这是针对您在 "As for a variable i tried the following but failed:"
下方提到的特定问题的最小编辑解决方案