Perl - 连接具有相似名称模式的文件,并将连接的文件名写入列表

时间:2016-04-01 18:13:05

标签: perl concatenation

我有一个包含多个子目录的目录,每个子目录都有一组固定的文件 - 每个类别对应一个 -

1)Main_dir
1.1) Subdir1 with files 

 - Test.1.age.txt
 - Test.1.name.txt
 - Test.1.place.csv
..........
1.2) Subdir2 with files 
 - Test.2.age.txt
 - Test.2.name.txt
 - Test.2.place.csv
.........

大约有20个文件夹,其中包含10个文件。我需要先将每个类别下的文件(如Test.1.age.txt和Test.2.age.txt)连接到combined.age.txt文件中,一旦我完成所有连接,我想在新的Final_list中打印出这些文件名。 txt文件如

./Main_dir/Combined.age.txt
./Main_dir/Combined.name.txt

我能够读取数组中所有子目录中的所有文件,但我不知道如何对类似的文件名进行模式搜索。此外,将能够找出代码的打印输出部分。任何人都可以分享如何进行此模式搜索连接?到目前为止我的代码:

use warnings;
use strict;
use File::Spec;
use Data::Dumper;
use File::Basename;

foreach my $file (@files) {
print "$file\n";
}
my $testdir = './Main_dir';
my @Comp_list = glob("$testdir/test_dir*/*.txt");

我正在尝试对@Comp_list中的数组内容进行模式搜索,我当然需要学习 -

foreach my $f1 (@Comp_list) {
        if($f1 !~ /^(\./\.txt$/) {
        print $f1; # check if reading the file right 


 #push it to a file using concatfile( 
}}

非常感谢!

2 个答案:

答案 0 :(得分:2)

如果您先对文件进行分类,然后就可以使用它们,我认为这样会更容易。

use warnings;
use strict;

use File::Spec;
use Data::Dumper;
use File::Basename;

my %hash = ();

my $testdir = './main_dir';
my @comp_list = glob("$testdir/**/*.txt");

foreach my $file (@comp_list){
    $file =~ /(\w+\.\d\..+\.txt)/;
    next if not defined $1;
    my @tmp = split(/\./, $1);
    if (not defined $hash{$tmp[-2]}) {
        $hash{$tmp[-2]} = [$file];
    }else{
        push($hash{$tmp[-2]}, $file);
    }
}

print Dumper(\%hash);

文件:

main_dir
├── sub1
│   ├── File.1.age.txt
│   └── File.1.name.txt
└── sub2
    ├── File.2.age.txt
    └── File.2.name.txt

结果:

$VAR1 = {
          'age' => [
                     './main_dir/sub1/File.1.age.txt',
                     './main_dir/sub2/File.2.age.txt'
                   ],
          'name' => [
                      './main_dir/sub1/File.1.name.txt',
                      './main_dir/sub2/File.2.name.txt'
                    ]
        };

您可以创建一个循环来连接和组合文件

答案 1 :(得分:2)

这对你有用。我只是在表面上对它进行了测试,因为我需要一段时间来创建一些测试数据,所以当你手边有一些我希望你能够报告任何问题时

该程序会隔离相当于glob次调用的所有文件,并根据其类型将它们放入存储桶中。我已经假设名称​​正好,因为您已经显示,所以当文件名在点上分割时,类型是倒数第二个字段;即Test.1.age.txt的类型为age

收集完所有文件列表后,我使用了一种最初设计用于读取命令行中指定的所有文件的技术。如果将@ARGV设置为文件列表,那么<ARGV>操作将读取所有文件,就像它们是一个一样,因此可以轻松地将其复制到新的输出文件

如果您需要以特定顺序连接的文件,那么我将不得不修改我的解决方案。目前,它们将按glob返回它们的顺序进行处理 - 可能是文件名的词汇顺序,但你不应该依赖它

use strict;
use warnings 'all';
use v5.14.0;    # For autoflush method

use File::Spec::Functions 'catfile';

use constant ROOT_DIR => './Main_dir';

my %files;

my $pattern = catfile(ROOT_DIR, 'test_dir*', '*.txt');

for my $file ( glob $pattern ) {
    my @fields = split /\./, $file;
    my $type = lc $fields[-2];
    push @{ $files{$type} }, $file;
}

STDOUT->autoflush;    # Get prompt reports of progress

for my $type ( keys %files ) {

    my $outfile = catfile(ROOT_DIR, "Combined.$type.txt");
    open my $out_fh, '>', $outfile or die qq{Unable to open "$outfile" for output: $!};

    my $files = $files{$type};

    printf qq{Writing aggregate file "%s" from %d input file%s ... },
            $outfile,
            scalar @$files,
            @$files == 1 ? '' : 's';

    local @ARGV = @$files;
    print $out_fh $_ while <ARGV>;

    print "complete\n";
}