首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >perl查找::文件和智能匹配,生成损坏的双链接列表

perl查找::文件和智能匹配,生成损坏的双链接列表
EN

Stack Overflow用户
提问于 2012-08-21 04:45:42
回答 2查看 306关注 0票数 1

我试图编写一个程序,递归地将所有文件从某个顶点读取到数组中,然后从一个单独的文件中读取文件名行,如果前面的数组中存在这些文件名,则尝试打印这些文件名。

我的程序遍历目录结构中的43K文件,然后遍历文件中400行中的大约300行,然后提供一个壮观的"* glibc检测到的 perl:损坏的双链接列表: 0x0000000000a30740 **“。

我一点也不知道..。这会是“内存不足”类型的错误吗?我无法想象这不是因为主机有24G的内存。

你知道我哪里出问题了吗?我试图节省时间和精力,方法是将整个文件列表从子目录中读取一次到数组中,然后使用文件名为ARGV的较短的文件列表进行匹配。

这是我的代码:

代码语言:javascript
复制
  #!/usr/bin/perl
  use warnings;
  use strict;
  use diagnostics;

  use File::Find;
  use 5.010001;

  ## debug subroutine
  my $is_debug = $ENV{DEBUG} // 0;
  sub debug { print "DEBUG: $_[0]\n" if $is_debug };

  ## exit unless properly called with ARGV
  die "Please provide a valid filename: $!" unless $ARGV[0] && (-e $ARGV[0]);

  my @pic_files;
  my $pic_directory="/files/multimedia/pictures";

  find( sub {
     push @pic_files, $File::Find::name
        if -f && ! -d ;
     }, $pic_directory);

  open LIST, '<', $ARGV[0] or die "Could not open $ARGV[0]: $!";

  while(<LIST>) {
     chomp;
     debug "\$_ is ->$_<-";

     if ( @pic_files ~~ /.*$_/i ) {
        print "found: $_\n";
     } else {
        print "missing: $_\n";
     }
  }
  close LIST or die "Could not close $ARGV[0]: $!";

下面是该文件的示例:

代码语言:javascript
复制
DSC02338.JPG  
DSC02339.JPG  
DSC02340.JPG  
DSC02341.JPG  
DSC02342.JPG  
DSC02343.JPG  
DSC02344.JPG  
DSC02345.JPG  
DSC02346.JPG  
DSC02347.JPG 

以及义务错误:

代码语言:javascript
复制
missing: DSC02654.JPG   
DEBUG:  is ->DSC02655.JPG<-   
missing: DSC02655.JPG   
DEBUG:  is ->DSC02656.JPG<-   
missing: DSC02656.JPG   
*** glibc detected *** perl: corrupted double-linked list: 0x0000000000a30740 ***   
======= Backtrace: =========   
/lib/libc.so.6(+0x71bd6)[0x7fb6d15dbbd6]   
/lib/libc.so.6(+0x7553f)[0x7fb6d15df53f]  

提前感谢!

EN

回答 2

Stack Overflow用户

发布于 2012-08-21 08:53:48

这是一个非常低效的算法。您正在运行21,500 *n个regexes,其中n是列表中的文件数。我的猜测是,这会让你陷入某种潜在的内存问题或错误。

这里有一种替代方法,如果不进行许多更改,效率就会高得多。首先,将文件读入散列,而不是数组(我添加了lc以使所有内容都小写,因为您想要大小写不敏感的匹配):

代码语言:javascript
复制
  my %pic_files;

  find( sub {
     $pic_files{lc $File::Find::name}++
        if -f && ! -d ;
     }, $pic_directory);

编辑:第二,与其使用regex搜索目录中的每个文件,不如在输入行上使用regex智能地查找潜在的匹配项。

代码语言:javascript
复制
my $path_portion = lc $_;
my $found = 0;
do {
     if (exists $pic_files{$path_portion} or exists $pic_files{'/' . $path_portion} )
     {
         $found = 1;
     }
} while (!found and $path_portion =~ /\/(.*)$/ and $path_portion = $1);

if ($found) { print "found: $_"; }
else { print "not found: $_\n"; }

这将检查输入文件中的路径,然后每次路径中的第一个目录与其不匹配时删除路径中的第一个目录,然后再次检查。它应该会快得多,并且希望这个奇怪的bug能够消失(尽管很高兴知道发生了什么;如果它是Perl中的一个bug,那么您的版本就变得非常重要,因为智能匹配是一个新特性,它最近进行了大量的更改和错误修复)。

票数 1
EN

Stack Overflow用户

发布于 2012-08-21 11:33:53

虽然我以前没有见过这样的错误,但我怀疑它是由生成43,000个元素的文件列表并在智能匹配中使用而引起的。您正在使用64位perl吗?

当您只需要匹配基本文件名时,存储到每个文件的完整路径也会使事情变得更加困难。

这确实不是智能匹配的好处,我建议您在输入文件中创建文件名的散列,并在find遇到它们时逐个标记它们。

这个节目展示了这个想法。我手头没有perl安装程序,所以我无法测试它,但它看起来还可以

代码语言:javascript
复制
use strict;
use warnings;

use File::Find;

my $listfile = shift;
die "Please provide a valid filename" unless $listfile;
open my $list, '<', $listfile or die "Unable to open '$listfile': $!";

my %list;
while (<$list>) {
  chomp;
  $list{$_} = 0;
}
close $list;

my $pic_directory = '/files/multimedia/pictures';

find( sub {
  if (-f and exists $list{$_}) {
    print "found: $_\n";
    $list{$_}++;
  }
}, $pic_directory);

for my $file (keys %list) {
  print "missing: $_\n" unless $list{$file};
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12048566

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档