【问题标题】:Reading Unix find(1) output into a hash rather than array将 Unix find(1) 输出读入散列而不是数组
【发布时间】:2016-07-07 05:18:32
【问题描述】:

自学,但想知道如何将 UNIX 查找命令的输出放入散列而不是数组。

我知道这行得通:

@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 新手(刚开始学习),但我们将不胜感激。

【问题讨论】:

  • 有什么特别的原因需要致电find吗? File::FindFile::Find::Rule 相当有效。
  • $variable = qx(...) 会将整个响应字符串放入标量变量中,而不是像数组那样分成行。 $hash_file{$some_extension} = $variable 只会将该字符串复制到散列元素,具体取决于$some_extension 的值。但目前还不清楚你实际上想要做什么。你想在你的哈希中做什么?我猜您正在尝试按扩展名过滤名称列表?
  • 是的 Borodin 这正是我想要做的。关于如何做到这一点的任何指示?

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


【解决方案1】:

这里是快速而肮脏的提示

#!/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

【讨论】:

    【解决方案2】:

    您可以使用 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" ;
      }
    }
    

    在大量文件上,通过将 -&gt;all() 方法替换为 -&gt;all_fast() 或移动过滤部分(即对any()fileparse()) 的调用进入一个自定义规则,该规则使用匿名子例程sub{ ...} 直接构造过滤后的文件列表。

    使用“惰性”迭代器方法-&gt;iter()-&gt;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() 是最快的。不过,快速并不总是“最好的”。 perl 模块可以为您提供错误处理和安全性,否则您将无法通过简单地读取系统命令的输出来获得。

    其他参考资料

    • Finding files with Perl 对更具体的File::Find 问题有一些很好的回答,并且在相关部分有一些很好的链接。

    • 您的问题也更笼统地涉及 perl 中的数据结构,因此您可能希望阅读系统上可用的“Perl 数据结构说明书”文档perldoc perldsc

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 2011-07-02
      • 2017-12-21
      • 2010-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多