读取Unix查找(1)输出到哈希而不是数组

时间:2016-03-20 19:31:44

标签: perl data-structures hash find perl-data-structures

我自己学习但想知道如何将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的新手(刚刚开始学习),但我们将非常感谢任何帮助。

2 个答案:

答案 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()内置函数创建一个以文件名作为键的哈希值,并将值设置为undef1或其他一些更有用的值:

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