【问题标题】:How can I break out of recursive find function once a specific file is found?找到特定文件后,如何摆脱递归查找功能?
【发布时间】:2010-09-27 17:45:22
【问题描述】:

我正在使用File::Find 模块来遍历目录树。找到特定文件后,我想停止搜索。我该怎么做?

   find (\$processFile, $mydir);

   sub processFile() {
      if ($_ =~ /target/) {
         # How can I return from find here?
      }
   }

【问题讨论】:

  • 你的意思是“File::Find”模块,而不是“File::Found”?
  • 好的,谢谢。我编辑了问题。

标签: perl recursion file-find


【解决方案1】:

看来你将不得不死:

eval {
    find (\$processFile, $mydir);
};

if ( $@ ) {
   if ( $@ =~ m/^found it/ ) {
        # be happy
    }
    else ( $@ ) {
        die $@;
    }
}
else {
   # be sad
}


sub processFile() {
   if ($_ =~ /target/) {
      die 'found it';
   }
}

【讨论】:

  • 这似乎有效。我对 perl 很陌生 - 这是 eval 的典型用法吗?
  • 非常。见perldoc -f eval
  • 基本上是没有类的例外。如果您想拥有更多控制权并确保它不仅仅是与“找到它”匹配的其他错误,您可以使用 Exception::Class 之类的东西。
  • 是的,奇怪的是 eval 是捕获 die 的主要方法......而且由于相当多的内置 die(例如 use),它是捕获它们的唯一方法。在您问“为什么要抓住使用中的骰子?”之前这是查看模块是否安装的最简单方法。
  • 你不需要使用 Exception::Class。您可能会死于“FIND_FILE:FOUND_MY_FILE”之类的内容,测试错误消息 ($@) 并(几乎)确定您找到了文件,并且没有遇到其他错误。
【解决方案2】:

除了其他人说的,你不妨看看File-Find-Object,它既是迭代的(并且因此能够在中间被打断)并且能够实例化(因此你可以启动和使用一次几个,或者在执行另一次扫描时实例化一个基于 FFO 对象等)

它的缺点是它不是核心,但它只有 Class::Accessor 作为依赖项,并且是纯 Perl,所以它应该不难安装。

我应该警告你,我是它的维护者,所以我可能有点偏见。

【讨论】:

    【解决方案3】:

    你能在 Perl 中抛出自定义异常吗?

    【讨论】:

    • 我认为有一个模块可以解决这个问题,但它是一个 hack。
    • 只需将对象传递给 die() 而不是字符串。
    【解决方案4】:

    如果你找到你的结果,你可以使用命名块并跳转到它(下一个,最后一个,这取决于你的需要)。

    【讨论】:

      【解决方案5】:

      我找到了这个链接:

      http://www.perlmonks.org/index.pl?node_id=171367

      我复制了该帖子列表中的一个脚本,这似乎有效:

      #! /usr/bin/perl -w
      
      use strict;
      use File::Find;
      
      my @hits = ();
      my $hit_lim = shift || 20;
      
      find(
          sub {
              if( scalar @hits >= $hit_lim ) {
                  $File::Find::prune = 1;
                  return;
              }
              elsif( -d $_ ) {
                  return;
              }
              push @hits, $File::Find::name;
          },
          shift || '.'
      );
      
      $, = "\n";
      print @hits, "\n";
      

      看起来实际上是通过使用 $File::Find::prune 导致 find 不再遍历。

      【讨论】:

      • 我尝试设置 $File::Find::prune 但没有成功。似乎在目录上设置 prune 会阻止 find 下降到该目录,但不会阻止它继续处理其他目录(或文件)。
      • 好的 - 当我在上面运行该脚本时,它会在 20 个结果处被切断,据我所知,它也停止了查找功能。 (添加“返回”可能会阻止结果被添加到数组中,但我很确定 File::Find 实际上正在停止)。对不起,它不适合你...
      【解决方案6】:

      如果找到文件,函数 processFile() 应该返回 true,否则返回 false。所以,每次 processFile 调用自己时都应该检查这个返回值。如果为真,则递归调用已找到该文件,因此无需再次调用自己,它也必须返回真。如果为 false,则该文件尚未找到,应继续搜索。

      【讨论】:

      • File::Find 可能不正确,但它是手动递归搜索函数的正确方式(所有递归函数都必须有终止方式,这是一种可接受的方式这样做)。
      猜你喜欢
      • 2015-05-13
      • 2020-11-07
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 2011-08-21
      • 1970-01-01
      • 2020-06-25
      相关资源
      最近更新 更多