perl Find ::文件和智能匹配产生损坏的双链表

时间:2012-08-21 04:45:42

标签: perl find

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

我的程序通过目录结构中的43K文件进行搅拌,然后在向我提供一个“ * glibc检测到的 perl:损坏的双链表:0x0000000000a30740 * *“

我根本不知道..这可能是一个'内存不足'类型的错误吗?我无法想象它不是因为主机有24G的内存。

你知道我哪里出错吗?我试图通过将子目录中的整个文件列表一次性读入数组并随后使用文件名为ARGV [0]的较短文件列表进行匹配来节省时间和精力。

这是我的代码:

  #!/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]: $!";

以下是该文件的示例:

DSC02338.JPG  
DSC02339.JPG  
DSC02340.JPG  
DSC02341.JPG  
DSC02342.JPG  
DSC02343.JPG  
DSC02344.JPG  
DSC02345.JPG  
DSC02346.JPG  
DSC02347.JPG 

和责任错误:

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]  

提前致谢!

2 个答案:

答案 0 :(得分:1)

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

这是一种替代方法,如果没有很多变化,效率会更高。首先,将文件读入散列而不是数组(我添加了lc以使所有内容都小写,因为您需要不区分大小写的匹配):

  my %pic_files;

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

编辑:其次,不是使用正则表达式搜索目录中的每个文件,而是使用输入行上的正则表达式来智能地找到潜在的匹配项。

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 :(得分:0)

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

当您需要匹配的所有内容都是基本文件名时,通过存储每个文件的完整路径,您也会变得更加困难。

这真的不是智能匹配的好处,我建议您应该在输入文件中创建文件名的哈希值,并在find遇到时逐个标记它们它们

这个程序显示了这个想法。我手边没有perl安装,所以我无法测试它,但它看起来不错

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};
}