所以,我这个目录的文件名是这样的:
HG00119.mapped.ILLUMINA.bwa.GBR.low_coverage.20101123.bam.bai
HG00119.mapped.ILLUMINA.bwa.GBR.exome.20120522.bam_herc2_data.bam
HG00117.mapped.illumina.mosaik.GBR.exome.20110411.bam_herc2_phase1.bam
HG00117.mapped.illumina.mosaik.GBR.exome.20110411.bam.bai
NA20828.mapped.illumina.mosaik.TSI.exome.20110411.bam_herc2_phase1.bam
NA20828.mapped.ILLUMINA.bwa.TSI.low_coverage.20130415.bam_herc2_data.bam
我有一个包含在每行中的input.txt文件。
NA20828
HG00119
如您所见,input.txt文件具有目录中文件名称的开头。
我想要做的是在input.txt中过滤目录中具有名称(在本例中只是开头)的文件。 我不知道自己是否清楚,但这是我迄今为止所做的代码。
use strict;
use warnings;
my @lines;
my @files = glob("*.mapped*");
open (my $input,'<','input.txt') or die $!;
while (my $line = <$input>) {
push (@lines, $line);
}
close $input;
我使用glob来只过滤名称中映射的文件,因为我有其他文件,我不想查找。
我尝试了一些foreach循环,尝试了grep和regex,我很确定我的方法是正确的,我认为我的错误可能与范围有关。
我很感激任何帮助的人!谢谢!
答案 0 :(得分:1)
好的,首先关闭 - 你的while循环是多余的。如果从列表上下文中的文件句柄读取,它会读取整个内容。
my @lines = <$input>;
将与while循环相同。
现在,对于您的模式 - 您将一个列表与另一个列表匹配,但部分匹配。
chomp ( @lines );
foreach my $file ( @files ) {
foreach my $line ( @lines ) {
if ( $file =~ m/$line/ ) { print "$file matches $line"; }
}
}
(是的,像grep或map这样的东西可以做到这一点,但我总觉得这两个让我头疼 - 它们更整洁,但是它们是隐式循环的,所以你并没有真正获得太多的算法效率)。
答案 1 :(得分:1)
您可以根据input.txt
的内容构建正则表达式
my @lines = do {
open my $fh, '<', 'input.txt' or die $!;
<$fh>;
};
chomp @lines;
my $re = join '|', @lines;
然后使用
找到所需的文件my @files = grep /^(?:$re)/, glob '*.mapped*';
请注意,如果input.txt
中的列表包含任何正则表达式元字符,例如.
,*
,+
等,则需要将其转义,可能使用quotemeta
喜欢这个
my $re = join '|', map quotemeta, @lines;
并且最好还是这样做,除非你某些 永远不会成为文件中的此类字符。