Perl-连接具有相似名称的文件模式,并将连接的文件名写入列表
我有一个包含多个子目录的目录,每个子目录都有一组固定的文件——每个类别一个,如-Perl-连接具有相似名称的文件模式,并将连接的文件名写入列表,perl,concatenation,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个文件夹,其
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)连接到一个组合的.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_列表中的数组内容进行模式搜索,我当然需要学习-
foreach my $f1 (@Comp_list) {
if($f1 !~ /^(\./\.txt$/) {
print $f1; # check if reading the file right
#push it to a file using concatfile(
}}
非常感谢 我认为如果你先对文件进行分类,然后再处理它们会更容易
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'
]
};
您可以创建一个循环来连接和组合文件我认为如果您先对文件进行分类,然后再使用它们,会更容易
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'
]
};
您可以创建一个循环来连接和组合文件这应该适合您。我只是对它进行了表面测试,因为创建一些测试数据需要一些时间,所以您手头有一些测试数据,我希望您能报告任何问题 该程序将通过等价的
glob
调用隔离找到的所有文件,并根据它们的类型将它们放入存储桶中。我假设名称与您显示的完全相同,因此当文件名被拆分为点时,类型是倒数第二个字段;i、 e.Test.1.age.txt的类型是age
收集了所有文件列表后,我使用了一种最初设计用于读取命令行上指定的所有文件的技术。如果将@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";
}
使用严格;
使用“全部”警告;
使用v5.14.0;#自动冲洗法
使用File::Spec::Functions'catfile';
使用常量ROOT_DIR=>'./Main_DIR';
我的%s文件;
my$pattern=catfile(ROOT_DIR、'test_DIR*'、'*.txt');
对于我的$文件(glob$模式){
my@fields=split/\./,$file;
my$type=lc$字段[-2];
推送@{$files{$type}},$file;
}
标准输出->自动刷新;#及时获取进度报告
对于my$类型(键%files){
my$outfile=catfile(ROOT_DIR,“Combined.$type.txt”);
打开我的$out_fh,'>',$outfile或死亡qq{无法打开输出的“$outfile:$!};
my$files=$files{$type};
printf qq{正在从%d个输入文件%s写入聚合文件“%s…”,
$outfile,
标量@$文件,
@$files==1?“”:“s”;
本地@ARGV=@$文件;
打印$out\u fh$\u同时;
打印“完成”\n;
}
这应该适合您。我只是对它进行了表面测试,因为创建一些测试数据需要一些时间,所以您手头有一些测试数据,我希望您能报告任何问题
该程序将通过等价的glob
调用隔离找到的所有文件,并根据它们的类型将它们放入存储桶中。我假设名称与您显示的完全相同,因此当文件名被拆分为点时,类型是倒数第二个字段;i、 e.Test.1.age.txt的类型是age
收集了所有文件列表后,我使用了一种最初设计用于读取命令行上指定的所有文件的技术。如果将@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";
}
使用严格;
使用“全部”警告;
使用v5.14.0;#自动冲洗法
使用File::Spec::Functions'catfile';
使用常量ROOT_DIR=>'./Main_DIR';
我的%s文件;
my$pattern=catfile(ROOT_DIR、'test_DIR*'、'*.txt');
对于我的$文件(glob$模式){
my@fields=split/\./,$file;
my$type=lc$字段[-2];
推送@{$files{$type}},$file;
}
标准输出->自动刷新;#及时获取进度报告
对于my$类型(键%files){
my$outfile=catfile(ROOT_DIR,“Combined.$type.txt”);
打开我的$out_fh,'>',$outfile或死亡qq{无法打开输出的“$outfile:$!};
my$files=$files{$type};
printf qq{正在从%d个输入文件%s写入聚合文件“%s…”,
$outfile,
标量@$文件,
@$files==1?“”:“s”;
本地@ARGV=@$文件;
打印$out\u fh$\u同时;
打印“完成”\n;
}
STDOUT->autoflush
是否需要模块?(当然,这是一个很好的答案)@zdim:autoflush
来自。它的子类,如果您使用的是PerlV5.14.0或laterOh。。。非常感谢你!我不知道。(我们在这里运行v5.10:(.非常感谢@Borodin,您的解决方案在我当前的一组文件上运行得非常好,但是正如您所指出的,如果我需要按照文件名的顺序排列,比如Test1.age.txt、Test2.age.txt、Test3.age.txt,我是否应该在文件名上运行循环并使用正则表达式检查数字?非常感谢!!STDOUT->autoflush
需要模块吗?(当然,这是一个很好的答案)@zdim:autoflush
来自它的subc