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

时间:2018-08-30 11:25:22

标签: regex perl

我写了以下脚本:

#!/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和文件夹2 / 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行的字符串。

我不知道该如何解决。您的单位将不胜感激。

1 个答案:

答案 0 :(得分:-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 pattern,其中可以包含wildcards。它仅返回与此模式匹配的文件。它不是正则表达式。
  • 您正在进行模式匹配,而忽略结果。

让我们仔细看看。

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,无论是否匹配。


我认为将所有压缩文件放到该目录中然后检查它们会更有意义。

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.";
}