我自己学习但想知道如何将UNIX find命令的输出放入哈希而不是数组。
我知道这有效:
@file_array= qx(find / -path '/{directory_path}/*' -type f -maxdepth 3
-name "{extension list}" 2>/dev/null );
但我想做这样的事情:
$variable = qx(find / -path '/{directory_path}/*' -type f -maxdepth 3
-name "{extension list}" 2>/dev/null);
$hash_file{$some_extension} = $variable;
我是perl的新手(刚刚开始学习),但我们将非常感谢任何帮助。
答案 0 :(得分:0)
这是快速&脏的提示
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use Data::Dumper;
my $Input = shift @ARGV;
my @SuffixList = qw(\.txt \.doc \.xls \.csv);
my $Suffixes = join '|', @SuffixList;
my $Sources = {};
my $MyDepth = 5;
find({
wanted => sub { my $Depth = tr!/!!;
push @{ $Sources->{$1} }, $_ if ($_ =~ m{($Suffixes)\z}xms
&& $Depth < $MyDepth)
},
no_chdir => 1,
}, $Input);
print Dumper $Sources;
tr的技巧来自here。
答案 1 :(得分:-1)
您可以使用map()
内置函数创建一个以文件名作为键的哈希值,并将值设置为undef
或1
或其他一些更有用的值:
perl -E 'map { $filehash{$_} = undef }
qx( find ./ -type f -maxdepth 3 2>/dev/null ) ;
say keys %filehash ;'
例如,您可以使用文件扩展名作为每个哈希键的值(从File::Basename
获取fileparse()
的扩展名):
perl -MFile::Basename -E '
map { chomp; $filehash{$_} = ( fileparse($_, qr/\..[^.]*$/))[2] }
qx( find ./ -type f -maxdepth 3 2>/dev/null ) ;
say "$_ has $filehash{$_} extension" for keys %filehash ;'
然后您可以使用以下内容进行过滤:
perl -MFile::Basename -E '
map { chomp; $files_ext{$_} = ( fileparse($_, qr/\..[^.]*$/))[2] }
qx( find ./ -type f -maxdepth 3 2>/dev/null ) ;
for $k (keys %files_ext) { say $k if $files_ext{$k} eq ".pdf" } ;'
然后您可以将其重写为脚本:
use v5.22;
use File::Basename ;
use List::Util 'any';
my %files_ext ;
my @ext = qw(.doc .xls) ;
my @list = qx( find ./ -type f -maxdepth 3 2>/dev/null ) ;
map {
chomp;
$files_ext{$_} = ( fileparse($_, qr/\..[^.]*$/))[2]
} @list ;
for my $k (keys %files_ext) {
say $k if (any { $_ eq $files_ext{$k} } @ext ) ;
}
但是,您可以使用各种模块之一来帮助您使用perl查找文件,而无需运行系统命令来执行此操作,而不是通过这种方式构建哈希来过滤文件。 例如 File::Find
附带核心perl发行版。来自CPAN我最喜欢的一个是Path:::Iterator::Rule
。由于您的问题询问如何将find
的输出添加到哈希,我的回答主要集中在该方法上。
以下是使用Path::Iterator::Rule
查找文件然后按上述方式过滤结果的脚本。
use File::Basename ;
use List::Util 'any';
use Path::Iterator::Rule;
my @exts = qw(.doc .xls);
my $rule = Path::Iterator::Rule->new()->max_depth(3);
my @dirs = $rule->all( "." ) ;
for my $file ( @dirs ) {
if ( any { $_ eq ( fileparse($file, qr/\..[^.]*$/))[2] } @exts ) {
print "$file \n" ;
}
}
在大量文件集上,可以通过将Path::Iterator::Rule
方法替换为->all()
或更快,使其更快(请参阅->all_fast()
文档的PERFORMANCE部分)将过滤部分(即对any()
和fileparse()
的调用)转换为使用匿名子例程sub{ ...}
直接构造过滤文件列表的自定义规则。
使用&#34;懒惰&#34;迭代器方法->iter()
或->iter_fast()
而不是列表界面似乎也有帮助:
use File::Basename;
use List::Util 'any';
use Path::Iterator::Rule;
my @exts = qw(.doc .xls);
my $rule = Path::Iterator::Rule->new()->max_depth(3);
$rule->and(
sub {
my $ext = ( fileparse($_, qr/\..[^.]*$/))[2];
any { $_ eq $ext } @exts;
}
);
my $next = $rule->iter_fast(".");
while (defined(my $file = $next->())) {
print "$file\n";
}
在我的系统上使用系统调用Unix find()
是最快的。快速并不总是&#34;最好&#34;虽然。 perl模块可以为您提供错误处理和安全性,否则您只需简单地输入系统命令即可获得。
其他参考资料
Finding files with Perl对更具体的File::Find
问题有一些很好的回答,并且在相关部分中有一些很好的链接。
您的问题也更普遍地讲述了perl中的数据结构,因此您可能希望阅读&#34; Perl数据结构手册&#34;您的系统上提供的文档为perldoc perldsc
。