我有一个文件,该文件基本上包含如下所示的值的排列方式(我已对行进行编号。)
! MATCH 1
! 2
HIT 3
NUM 1 4
VAL A 82 5
LEU A 144 6
ALA A 154 7
VAL A 333 8
ALA A 334 9
PHE A 372 10
END 11
! 12
我正在尝试创建一个文件,其中包含所有这些实例,其中这些值块在第10行中包含上述的PHE(与ALA或VAL等相对)。
文件中多个值块的简短示例:
! MATCH
!
HIT
NUM 1
VAL A 184
PHE A 209
END
!
! MATCH
!
HIT
NUM 1
LEU A 296
ILE A 321
END
!
! MATCH
!
HIT
NUM 1
LEU A 296
PHE A 321
END
!
我尝试执行此操作的代码是:
sed -n '23~12p' file.txt | grep -B 9 -A 2 PHE > newfile.txt
基本上,从第23行开始,每12行跳过一次(以便仅查看值块的第10行),然后grep前9行,如果值块的第10行中存在PHE,则grep接下来的2行。
但是,我敢肯定,您可以说,上面的代码仅在sed输出中输出前几行。
sed -n '23~12p' file.txt | grep -B 9 -A 2 PHE file.txt > newfile.txt
但是,如果我为grep添加文件(file.txt),即使PHE不在值块的第十行,它也会忽略sed输出,而是抓紧前几行。
IE:
ILE A 222
END
!
! MATCH
!
HIT
NUM 1
ILE A 605
ILE A 620
PHE A 644 <--- What grep is matching
VAL A 633
ALA A 634
我对如何编写此脚本以在我要查找的位置(位置10)搜索PHE,每12行查找一次,并grepping整个值块(前9个)感到有些困惑行和随后的2行)仅在位置10处找到PHE时。
将非常感谢任何建议!谢谢!
答案 0 :(得分:3)
假定这些块用空行分隔
perl -00 -wne'print if (split /\n/)[9] =~ /^PHE/' data.txt
有关命令行开关,请参见perlrun。在这里,-00
将输入分为几段,然后在special variable $_
中''
下的程序中可用。那是换行符上的split,第十行用正则表达式检查它是否以PHE
开头。如果是,我们将打印整个块。
已阐明,没有专用的块分隔符;块彼此接连出现,每个块都以! MATCH
行开始,以!
行结束。
然后,由于$/
的{{1}}(可通过!
开关设置)会引入虚假的输入记录,因此上述内容在过滤后无法轻易保留整个块。而是逐行处理。
使用问题更新中添加的数据示例
-0\x21
每行都添加到缓冲区(或“块”)perl -ne'
if (/^\! MATCH/ or eof) { $b[5]=~/^PHE/ and print for @b; @b=() };
push @b, $_
' data.txt
中。以@b
开头的行开始一个新块,因此,如果它的第六行以! MATCH
开头(在真实数据PHE
中),则打印前一个,并清空下一个块的缓冲区。>
$b[9]
是必需的,因此对于输入的最后一个块/缓冲区,也要这样做。
我可以建议在写入此文件时在记录之间插入空白行。
答案 1 :(得分:1)
听起来这可能是您要尝试执行的操作:
$ awk '
{ recLine = NR%8 }
{ rec = (recLine==1 ? "" : rec ORS) $0 }
recLine==6 { f = /PHE/ }
(recLine==0) && f { print rec }
' file
! MATCH
!
HIT
NUM 1
VAL A 184
PHE A 209
END
!
! MATCH
!
HIT
NUM 1
LEU A 296
PHE A 321
END
!
只需将您的真实数据更改为8到12和6到10。
答案 2 :(得分:1)
这是一个易于理解和可扩展的脚本。
#!/usr/bin/env perl
use strict;
my $matchNum=0;
my @match;
while (<STDIN>) {
chomp;
if (/^! MATCH$/) {
@match and checkMatch(\@match, \$matchNum);
@match=($_);
} else { push @match, $_ }
}
@match and checkMatch(\@match, \$matchNum);
sub checkMatch {
my ($matchAR, $matchNumSR) = @_;
++$$matchNumSR;
if ( $matchAR->[9] =~ /^PHE/ ) {
print "Match $$matchNumSR = $matchAR->[9]\n";
}
}
答案 3 :(得分:1)
这可能对您有用(GNU sed):
sed -n '14~12{h;b};H;23~12{/^PHE/!{x;z;x}};25~12{x;/^\n/!p;x}' file
设置类似grep的选项-n
。从第14行开始,然后以12为模,将保持空间设置为当前行并脱离sed脚本。对于所有其他行,请将当前行追加到保留空间。在第23行和其后的模12处,检查当前行以开始PHE
,如果没有清除保留空间,请检查。在第25行和其后的模12处,检查保留空间,如果它不是以换行开头,则在保留空间中打印所有12行。
如果在第23行和以12为模,及其后的行,当前行没有开始PHE
,则保持将被清除,并添加后续行。附加的行之前有换行符,因此,如果保留空间以换行符开头,则对PHE
的检查将失败,并且可以丢弃这些行。
替代方法:
sed -r '1,13d;:a;N;s/[^\n]*/&/12;Ta;/^([^\n]*\n){9}PHE/p;d' file
删除前13行。聚集12行,并在第10行以PHE
开始时打印它们。