用于扫描目录树的Perl递归代码 [英] Perl recursive code for scanning directory tree

查看:57
本文介绍了用于扫描目录树的Perl递归代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在此脚本中,它以递归方式扫描目录,我想知道调用"ScanDirectory($ name)"时会发生什么->"next"是否紧接着执行?

In this script that scan a directory recursively, i would like to know what happen when the "ScanDirectory($name)" is called -> does the "next" get executed right after?

如果在每次循环后@names都填充有新目录,则我们进入@names中的第一个目录,如果还有其他目录,则会再次调用Scandirectory,但以前的@names中的其他目录将被替换并这样它们就不会被循环处理吗?抱歉,如果我没有道理.

Cause if the @names gets populated with new directories after each loop then we get inside the first directory in @names, and if there is other directories there Scandirectory is called again but the other directories in the previous @names are replaced and so they are not treated by the loop? Sorry if i don't make sense.

我知道已经有一个用于此目的的模块,但是我想提高对这种循环代码如何工作的理解,以便在其他情况下可以处理递归代码

i know there is already a module for this purpose, but i want to improve my understanding of how this loop code works so i can deal with recursive code in other situations

sub ScanDirectory {

  my $workdir = shift;
  my $startdir = cwd;

  chdir $workdir or die;
  opendir my $DIR, '.' or die;
  my @names = readdir $DIR or die;
  closedir $DIR;

  foreach my $name (@names) {
    next if ($name eq ".");
    next if ($name eq "..");

    if (-d $name) {
      ScanDirectory($name);
      next;
    }

  }
  chdir $startdir or die;
}

ScanDirectory('.');

推荐答案

这是您的代码吗?

在子例程中,调用 my @names = readdir ,它定义了一个新的词法范围变量,因此每次递归都会创建该变量的新实例.如果您使用 our 而不是 my ,它可能会起作用.用 our 定义的变量是打包范围,这意味着每个调用将使用相同的 @names 变量.其实还没有.您正在使用 readdir 清除变量的先前值.

In the subroutine you call my @names = readdir that defines a new lexically scoped variable, so each recursion will create a new instance of that variable. It might work if you use our instead of my. Variables defined with our are packaged scope which means each call will use the same @names variable. Actually not even then. You're cleaning out the previous value of the variable with your readdir.

使用 File :: Find 会更好. File :: Find 随大多数Perl安装一起提供,因此始终可用.

You'll be better off using File::Find. File::Find comes with most Perl installations, so it's always available.

use strict;
use warnings; 

use File::Find;

my @names;
find ( sub {
          next if $_ eq "." or $_ eq "..";
          push @names, $File::Find::name;
     }, "."
);

由于它不递归地调用自身,因此更易于理解,更易于编写,更灵活且效率更高.在大多数情况下,您会在没有 sub 嵌入函数的情况下看到这种情况:

This is simpler to understand, easier to write, more flexible, and much more efficient since it doesn't call itself recursively. Most of the time, you'll see this without the sub being embedded in the function:

my @names;
find ( \&wanted, ".");

sub wanted {
    next if $_ eq "." or $_ eq "..";
    push @names, $File::Find::name;
}

如果子例程很小,我更喜欢嵌入子例程.这样可以防止子例程脱离 find 调用,并且可以防止在未明确定义的情况下在子例程中使用 @names 的神秘实例.

I prefer to embed the subroutine if the subroutine is fairly small. It prevents the subroutine from wandering away from the find call, and it prevents the mysterious instance of @names being used in the subroutine without a clear definition.

好的,他们都是一样的.两者都是子例程引用(一个称为 wanted ,一个是匿名子例程).但是,第一次使用 @names 看起来并没有那么神秘,因为它是在 find 调用上方的行上按字面定义的.

Okay, they're both the same. Both are subroutine references (one is called wanted and one is an anonymous subroutine). However, the first use of @names doesn't appear so mysterious since it's literally defined on the line right above the find call.

如果必须从头开始编写自己的例程(也许是一项家庭作业?),则不要使用递归.使用 push 反向 readdir 推入数组.

If you must write your own routine from scratch (maybe a homework assignment?), then don't use recursion. use push to push the reversed readdir into an array.

然后,一次弹出一个数组项.如果找到目录,请再次读取该目录并将其推入阵列.注意. .. .

Then, pop off the items of the array one at a time. If you find a directory, read it (again in reverse) and push it onto your array. Be careful with . and ...

这篇关于用于扫描目录树的Perl递归代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆