Perl,匹配目录的文件,使用包含这些文件名的一部分的数组

Perl, matching files of a directory, using an array with part of the these file names

所以,我有这个目录,其中包含这样命名的文件:

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,我很确定我的方向是正确的,我认为我的错误可能与范围有关。

我将不胜感激任何帮助!谢谢!

好的,首先 - 你的 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 这样的东西可以做到这一点,但我总是发现这两个让我头疼 - 它们更整洁,但它们隐式循环所以你并没有真正获得太多算法效率).

您可以像这样从 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;

而且最好还是这样做,除非您确定文件中永远不会有这样的字符。