合并来自不同目录的具有相同前缀的文件

问题描述 投票:0回答:1

我写了以下脚本:

#!/usr/bin/perl -w

use strict;

die "usage:$0 <Input_folder_1>\t<Input_folder_2>\t<Out_folder>\t<Project_name>\t\n" unless $#ARGV == 3;

my $folder1 = shift;
#print "$folder1\n";
my $folder2 = shift;
#print "$folder2\n";
my $out = shift;
my $project_name = shift;

my $file1;
my $file2;
my $file3;
my $file4;

#print "$project_name\n";
foreach(glob("$folder1/$project_name\_S[0-9]_R1_001.fastq.gz")){
    chomp;
    #print "Hello World\n";
    $_ =~ m{$folder1/$project_name\_S[0-9]_R1_001\.fastq.gz};
        #print "$_\n";
        $file1 = $_;
        print "$file1\n";
}

foreach(glob("$folder2/$project_name\_S[0-9]_R1_001.fastq.gz")){
    chomp;
    #print "Hello World\n";
    $_ =~ m{$folder2/$project_name\_S[0-9]_R1_001\.fastq.gz};
        #print "$_\n";
        $file2 = $_;
        print "$file2\n";
}

cat $file1 $file2 > $out/$project_name.R1.fastq.gz; #line 42

foreach(glob("$folder1/$project_name\_S[0-9]_R2_001.fastq.gz")){
    chomp;
    #print "Hello World\n";
    $_ =~ m{$folder1/$project_name\_S[0-9]_R2_001\.fastq.gz};
        #print "$_\n";
        $file3 = $_;
        print "$file3\n";
}

foreach(glob("$folder2/$project_name\_S[0-9]_R2_001.fastq.gz")){
    chomp;
    #print "Hello World\n";
    $_ =~ m{$folder2/$project_name\_S[0-9]_R2_001\.fastq.gz};
        #print "$_\n";
        $file4 = $_;
        print "$file4\n";
}

`cat $file3 $file4 > $out/$project_name.R2.fastq.gz`;

该脚本运行如下:

./script.pl folder1 folder2 output_folder project_name

当我使用以下文件运行此脚本时,它运行顺利

folder1/123-abcQ_S3_R1_001.fastq.gz
folder2/123-abcQ_S1_R1_001.fastq.gz
folder1/123-abcQ_S3_R2_001.fastq.gz
folder2/123-abcQ_S1_R2_001.fastq.gz

./script.pl folder1 folder2 out/ 123-abcQ 

它将合并文件folder1 / 123-abcQ_S3_R1_001.fastq.gz和folder2 / 123-abcQ_S1_R1_001.fastq.gz,以在输出目录中创建合并的123-abcQ.R1.fastq.gz文件。

但是,当我使用以下文件运行相同的脚本时,它会给我一个错误:

folder1/demo-1_S10_R1_001.fastq.gz
folder1/demo-1_S10_R2_001.fastq.gz
folder2/demo-1_S12_R1_001.fastq.gz
folder2/demo-1_S12_R2_001.fastq.gz

./script.pl folder1 folder2 out/ demo-1

在连接(。)中使用未初始化的值$ file1或在./script.pl第42行使用字符串。在连接(。)中使用未初始化的值$ file2或在./script.pl第42行使用字符串。

我无法弄清楚如何解决这个问题。您的建议将不胜感激。

regex perl
1个回答
-1
投票

使用第二组参数,您不应在警告之前看到任何输出。它不打印任何东西。

那是因为它不会从你的glob调用中返回任何文件,所以foreach循环实际上并没有被执行。 $file1最初是undef,现在永远不会被设定。

my $file1; # starts out as undef
# ...

#print "$project_name\n";
foreach(glob("$folder1/$project_name\_S[0-9]_R1_001.fastq.gz")){ # finds nothing
    chomp;
    #print "Hello World\n";
    $_ =~ m{$folder1/$project_name\_S[0-9]_R1_001\.fastq.gz};
        #print "$_\n";
        $file1 = $_;
        print "$file1\n"; # no output here
}

它可能找不到您的文件,因为您没有任何与该模式匹配的文件。

这里有两件事:

  • glob采取可以包含a sort of patternwildcards。它只返回与此模式匹配的文件。它不是正则表达式*。
  • 您正在进行模式匹配,并忽略结果。

让我们更仔细地看一下。

foreach(glob("$folder1/$project_name\_S[0-9]_R2_001.fastq.gz")){

有趣的是glob EXPR。你的表达是:

# | variable interpolation 
# |        | variable interpolation            
# |        |            | treat this as a literal underscore, not part of var name
# |        |            |  one digit out of group 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
# |        |            |  |   |
  $folder1/$project_name\_S[0-9]_R2_001.fastq.gz

这将返回与此模式匹配的文件列表。如果没有找到任何文件,则不返回任何内容。然后foreach循环迭代该列表。同样,如果列表中没有任何内容,则永远不会调用循环。

foreach ( glob ... ) {
    chomp;
    $_ =~ m{$folder1/$project_name\_S[0-9]_R1_001\.fastq.gz};
    $file1 = $_;

你现在用chomp切断了换行符。这没有任何意义,因为文件名通常最后没有换行符。

然后,您使用与glob相同的模式对文件名进行模式匹配。在这种情况下,它是一个实际的正则表达式,因此某些字符具有特殊含义。

m{
  $folder1        # variable interpolation
  /               # literal slash /
  $project_name   # variable interpolation
  \_S             # literal backslash \ and S
  [0-9]           # one digit from 0 to 9
  _R1_001         # literal string
  \.              # literal dot .
  fastq           # literal string
  .               # exactly one of any character
  gz              # literal string
};

如您所见,该模式意味着完全不同的东西。你逃脱了其中一个点.,但不是两个。

但这没关系,因为这个操作没有做任何事情。你只是扔掉了结果!

然后你将$_分配给$file1,无论是否匹配。


我认为只需获取该目录中的所有gzip压缩文件然后检查它们就更有意义了。

foreach my $filename ( glob <$folder1/${project_name}*.fastq.gz> ) {
    if ( $filename =~ m{
            /             # separates the folder from the filename
            $project_name # anchor to project
            _         
            [0-9]+        # one or more numbers (001, 123, 9, ...)
            _R1_001 
            \.fastq\.gz   # file type
            $             # end of string
        }x
     ) {
        $file1 = $filename;
        last;
    }
}

这使用其他glob语法,我发现它更具可读性,获取$folder1中以$project_name开头并以.fastq.gz结尾的所有文件。然后它迭代文件列表并执行模式匹配,以确保我们实际获得正确的文件。我已经包含了/x修饰符来忽略模式中的空格,所以我们可以有注释。

请注意[0-9]+,它表示一个或多个数字。这很重要,因此可以找到数字大于9的文件。

找到匹配后,它会分配$file1,然后使用last退出循环。

在运行使用$file1$file2的外部命令之前,您可能还想添加一个检查。

if ($file1 && $file2) {
     `cat $file1 $file2 > $out/$project_name.R1.fastq.gz`
} else {
     print "No matches found for first set of files.";
}
© www.soinside.com 2019 - 2024. All rights reserved.