仅当当前行满足给定条件时才保留当前行和上一行
Keep current and previous line only if current line fulfills a given condition
我有一个如下所示的文件:
>4RYF_1
MAENTKNENITNILTQKLIDTRTVLIYGEINQELAEDVSKQLLLLESISNDPITIFINSQGGHVEAGDTIHDMIKFIKPTVKVVGTGWVASAGITIYLAAEKENRFSLPNTRYMIHQPAGGVQGQSTEIEIEAKEIIRMRERINRLIAEATGQSYEQISKDTDRNFWLSVNEAKDYGIVNEIIENRDGLKMASWSHPQFEK
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
仅当序列具有给定长度时,我才想保留序列和上一行。为了仅选择符合该条件的行,我使用:
awk 'length([=11=]) > 50 && length([=11=]) <=800)' sample.txt
但是,如果满足此条件,我怎样才能保留以 > 开头的行呢?
AWK 的潜在解决方案是:
awk '!/^>/ {next}; {getline s}; length(s) > 50 && length(s) <= 800 { print [=10=] "\n" s }' example.fasta
例如如果 example.fasta
包含
>4RYF_1
WLSVNEAKDYGIVNEIIENRDGLKMASWSHPQFEK
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
>1000_chars
YiJOgeCApTkcJWxIuvooOxuqVnPdSLtOQmUfnzpBvcpYKyCvelFwKgMchYFnlvuZwVxNcnSvGcACsMywDQVvYBAiaIesQkLkYNsExRbqKPZIPnCRMAFHLmIzxIBqLwoNEPSKMZCTpwbbQCNrHSrbDMtCksTjvQsMeAkoudRGUJnPpQTEzwwnKoZBHtpMSIQBfYSPDYHwKktvCiFpewrsdDTQpqBajOWZkKURaKszEqDmdYMkzSAkMtlkXPfHroiTbyxZwzvrrMSXMRSavrBdgVYZanudjacRHWfpErJMkomXpzagXIzwbaeFgAgFnMxLuQHsdvZysqAsngkCZILvVLaFpkWnOpuYensROwkhwqUdngvlTsXBoCBwJUENUFgVdnSnxVOvfksyiabglFPqmSwhGabjNZiWGyvktzSDOQNGlEvoxhJCAOhxVAtZfyimzsziakpzfIszSWYVgKZTHatWSfttHYTkvgafcsVmitfEfQDuyyDAAAoTKpuhLrnHVFKgmEsSgygqcNLQYkpnhOosKiZJKpDolXcxAKHABtALqVXoVcSHpskrpWPrkkZLTpUXkENhnesmoQjonLWxkpcuJrOosXKNTDNuZaWIEtrDILXsIFTjAnrnwJBoirgNHcDURwDIzAXJSLPLmWkurOhWSLPrIOyqNvADBdIFaCGoZeewKleBHUGmKFWFcGgZIGUdOHwwINZqcOClPAjYaLNdLgDsUNCPwKMrOXJEyPvMRLaTJGgxzeoLCggJYTVjlJpyMsoCRZBDrBDckNMhJSQWBAxYBlqSpXnpmLeEJYirwjfCqZGBZdgkHzWGoAMxgNKHOAvGXsIbbuBjeeORhZaIrruBwDfzgTICuwWCAhCPqMqkHrxkQMZbXUIavknNhuIycoDssXlOtbSWsxVXQhWMyDQZWDlEtewXWKBPUcHDYWWgyOerbnoAxrnpsCulOxqxdywFJFoeWNpVGIPMUJSWwvlVDWNkjIBMlXPi
只会打印
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
编辑
我建议更好地处理边缘情况的方法是使用专门构建的生物信息学软件,例如seqkit
seqkit seq -m 50 -M 800 example.fasta
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDI
FLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEI
MIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEA
KDYGLIDDIIINKSGLKGHHHHHH
这是一条线:
LANG=C grep -B1 '^.\{51,800\}$' < sample.txt
我默认设置的 LANG=en_US.UTF-8 的命令真的很慢,所以改用 LANG=C。
man grep
告诉您“-B NUM”表示“在匹配行之前打印前导上下文的 NUM 行”。
'^'表示行首
'.'表示任意字符
'{51,800}' 表示我们想要前一个东西的 51 到 800
'$' 表示行尾。
或者换句话说,我们要匹配 51 到 800 个字符之间的行,并打印它和上一行。
请您尝试以下操作:
awk -v RS='>' -F'\n' '
length() > 50 && length() <= 800 {printf ">%s", [=10=]}
' sample.txt
将 RS
分配给 '>' 告诉 awk
将 >
上的文件拆分为记录,
在同一记录中处理 header 行和序列行。
将 FS
分配给 '\n' 将记录拆分到 header 和
序列,每个分配 </code> 到 header 和 <code>
到序列。
由于前导 >
作为定界符被砍掉了,我们需要在前面加上它
打印匹配记录时。
perl
是一个选项吗?
perl -nle '$prev && print if length() >50 and length() < 800 && print $prev; $prev = $_' input_file
$prev
- 创建一个变量来保存每一行。当满足长度条件,并且有前一行$prev
,则打印$prev
中匹配的条件,并打印最后一行
$prev = $_
将当前行分配给 prev
行变量
如果上限 800
不是必需的,sed
可以作为一个选项吗?
$ sed -En '/>/ {N;/[a-zA-Z0-9]{50,}/p}' input_file
/>/
- 匹配 >
并读入模式 space
N;
运行 匹配后下一行的条件并将其附加到模式 space also:
{50,}
- 如果长度为 50 或更多
/p
- Return 它并打印
输出
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
另一个awk
解决方案:
awk '/^>/ { header = [=10=]; next } length > 50 && length <= 800 { print header ORS [=10=] }'
如果只有下一行满足长度限制,可以将以>
开头的行匹配存储在一个变量中,例如previous
然后对于下一行,检查长度以及上一行是否为空。
如果不是,打印上一行和当前行。
最后,将前一个变量设置为空字符串。
awk '{
if (/^>/) {
previous = [=10=]
next
}
if (length(previous) != 0 && length([=10=]) > 50 && length([=10=]) <= 800) {
print previous ORS [=10=]
}
previous=""
}' sample.txt
看到 AWK demo
使用您显示的示例,请尝试以下 awk
代码。使用 GNU awk
.
编写和测试
awk -v RS= '
{
val=""
delete arr
while(match([=10=],/>[^\n]*\n*[^\n]*/)){
val=substr([=10=],RSTART,RLENGTH)
split(val,arr,"\n")
if(length(arr[2])>50 && length(arr[2])<=800){
print val
}
[=10=]=substr([=10=],RSTART+RLENGTH)
}
}
' Input_file
我有一个如下所示的文件:
>4RYF_1
MAENTKNENITNILTQKLIDTRTVLIYGEINQELAEDVSKQLLLLESISNDPITIFINSQGGHVEAGDTIHDMIKFIKPTVKVVGTGWVASAGITIYLAAEKENRFSLPNTRYMIHQPAGGVQGQSTEIEIEAKEIIRMRERINRLIAEATGQSYEQISKDTDRNFWLSVNEAKDYGIVNEIIENRDGLKMASWSHPQFEK
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
仅当序列具有给定长度时,我才想保留序列和上一行。为了仅选择符合该条件的行,我使用:
awk 'length([=11=]) > 50 && length([=11=]) <=800)' sample.txt
但是,如果满足此条件,我怎样才能保留以 > 开头的行呢?
AWK 的潜在解决方案是:
awk '!/^>/ {next}; {getline s}; length(s) > 50 && length(s) <= 800 { print [=10=] "\n" s }' example.fasta
例如如果 example.fasta
包含
>4RYF_1
WLSVNEAKDYGIVNEIIENRDGLKMASWSHPQFEK
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
>1000_chars
YiJOgeCApTkcJWxIuvooOxuqVnPdSLtOQmUfnzpBvcpYKyCvelFwKgMchYFnlvuZwVxNcnSvGcACsMywDQVvYBAiaIesQkLkYNsExRbqKPZIPnCRMAFHLmIzxIBqLwoNEPSKMZCTpwbbQCNrHSrbDMtCksTjvQsMeAkoudRGUJnPpQTEzwwnKoZBHtpMSIQBfYSPDYHwKktvCiFpewrsdDTQpqBajOWZkKURaKszEqDmdYMkzSAkMtlkXPfHroiTbyxZwzvrrMSXMRSavrBdgVYZanudjacRHWfpErJMkomXpzagXIzwbaeFgAgFnMxLuQHsdvZysqAsngkCZILvVLaFpkWnOpuYensROwkhwqUdngvlTsXBoCBwJUENUFgVdnSnxVOvfksyiabglFPqmSwhGabjNZiWGyvktzSDOQNGlEvoxhJCAOhxVAtZfyimzsziakpzfIszSWYVgKZTHatWSfttHYTkvgafcsVmitfEfQDuyyDAAAoTKpuhLrnHVFKgmEsSgygqcNLQYkpnhOosKiZJKpDolXcxAKHABtALqVXoVcSHpskrpWPrkkZLTpUXkENhnesmoQjonLWxkpcuJrOosXKNTDNuZaWIEtrDILXsIFTjAnrnwJBoirgNHcDURwDIzAXJSLPLmWkurOhWSLPrIOyqNvADBdIFaCGoZeewKleBHUGmKFWFcGgZIGUdOHwwINZqcOClPAjYaLNdLgDsUNCPwKMrOXJEyPvMRLaTJGgxzeoLCggJYTVjlJpyMsoCRZBDrBDckNMhJSQWBAxYBlqSpXnpmLeEJYirwjfCqZGBZdgkHzWGoAMxgNKHOAvGXsIbbuBjeeORhZaIrruBwDfzgTICuwWCAhCPqMqkHrxkQMZbXUIavknNhuIycoDssXlOtbSWsxVXQhWMyDQZWDlEtewXWKBPUcHDYWWgyOerbnoAxrnpsCulOxqxdywFJFoeWNpVGIPMUJSWwvlVDWNkjIBMlXPi
只会打印
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
编辑
我建议更好地处理边缘情况的方法是使用专门构建的生物信息学软件,例如seqkit
seqkit seq -m 50 -M 800 example.fasta
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDI
FLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEI
MIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEA
KDYGLIDDIIINKSGLKGHHHHHH
这是一条线:
LANG=C grep -B1 '^.\{51,800\}$' < sample.txt
我默认设置的 LANG=en_US.UTF-8 的命令真的很慢,所以改用 LANG=C。
man grep
告诉您“-B NUM”表示“在匹配行之前打印前导上下文的 NUM 行”。
'^'表示行首
'.'表示任意字符
'{51,800}' 表示我们想要前一个东西的 51 到 800
'$' 表示行尾。
或者换句话说,我们要匹配 51 到 800 个字符之间的行,并打印它和上一行。
请您尝试以下操作:
awk -v RS='>' -F'\n' '
length() > 50 && length() <= 800 {printf ">%s", [=10=]}
' sample.txt
将
RS
分配给 '>' 告诉awk
将>
上的文件拆分为记录, 在同一记录中处理 header 行和序列行。将
FS
分配给 '\n' 将记录拆分到 header 和 序列,每个分配</code> 到 header 和 <code>
到序列。由于前导
>
作为定界符被砍掉了,我们需要在前面加上它 打印匹配记录时。
perl
是一个选项吗?
perl -nle '$prev && print if length() >50 and length() < 800 && print $prev; $prev = $_' input_file
$prev
- 创建一个变量来保存每一行。当满足长度条件,并且有前一行$prev
,则打印$prev
中匹配的条件,并打印最后一行
$prev = $_
将当前行分配给 prev
行变量
如果上限 800
不是必需的,sed
可以作为一个选项吗?
$ sed -En '/>/ {N;/[a-zA-Z0-9]{50,}/p}' input_file
/>/
- 匹配 >
并读入模式 space
N;
运行 匹配后下一行的条件并将其附加到模式 space also:
{50,}
- 如果长度为 50 或更多
/p
- Return 它并打印
输出
>4RYF_2
MNLIPTVIEQTSRGERAYDIYSRLLKDRIIMLGSAIDDNVANSIVSQLLFLDAQDPEKDIFLYINSPGGSISAGMAIYDTMNFVKADVQTIGMGMAASMGSFLLTAGANGKRFALPNAEIMIHQPLGGAQGQATEIEIAARHILKIKERMNTIMAEKTGQPYEVIARDTDRDNFMTAQEAKDYGLIDDIIINKSGLKGHHHHHH
另一个awk
解决方案:
awk '/^>/ { header = [=10=]; next } length > 50 && length <= 800 { print header ORS [=10=] }'
如果只有下一行满足长度限制,可以将以>
开头的行匹配存储在一个变量中,例如previous
然后对于下一行,检查长度以及上一行是否为空。
如果不是,打印上一行和当前行。
最后,将前一个变量设置为空字符串。
awk '{
if (/^>/) {
previous = [=10=]
next
}
if (length(previous) != 0 && length([=10=]) > 50 && length([=10=]) <= 800) {
print previous ORS [=10=]
}
previous=""
}' sample.txt
看到 AWK demo
使用您显示的示例,请尝试以下 awk
代码。使用 GNU awk
.
awk -v RS= '
{
val=""
delete arr
while(match([=10=],/>[^\n]*\n*[^\n]*/)){
val=substr([=10=],RSTART,RLENGTH)
split(val,arr,"\n")
if(length(arr[2])>50 && length(arr[2])<=800){
print val
}
[=10=]=substr([=10=],RSTART+RLENGTH)
}
}
' Input_file