递归 Perl 详细信息需要帮助

发布于 2024-10-09 07:46:36 字数 937 浏览 4 评论 0原文

我认为这是一个简单的问题,但我已经坚持了一段时间了!我需要用一双新的眼光来看待这个问题。

问题是我在 perl 中有这段代码:

#!c:/Perl/bin/perl
use CGI qw/param/;  
use URI::Escape; 

print "Content-type: text/html\n\n";

my $directory = param ('directory'); 
$directory = uri_unescape ($directory); 

my @contents;
readDir($directory);


foreach (@contents) {
  print "$_\n";
}

#------------------------------------------------------------------------
sub readDir(){
 my $dir = shift;
    opendir(DIR, $dir) or die $!;
    while (my $file = readdir(DIR)) {
  next if ($file =~ m/^\./);
  if(-d $dir.$file)
  {
   #print $dir.$file. " ----- DIR\n";
   readDir($dir.$file);
  }
  push @contents, ($dir . $file);
    }
    closedir(DIR);
}

我试图让它递归。我需要拥有所有目录和子目录的所有文件以及完整路径,以便我将来可以打开这些文件。

但我的输出仅返回当前目录中的文件以及它找到的第一个目录中的文件。如果我的目录中有 3 个文件夹,它只显示第一个。

前任。 cmd 调用:

"perl readDir.pl directory=C:/PerlTest/"

谢谢

i think this is a simple problem, but i'm stuck with it for some time now! I need a fresh pair of eyes on this.

The thing is i have this code in perl:

#!c:/Perl/bin/perl
use CGI qw/param/;  
use URI::Escape; 

print "Content-type: text/html\n\n";

my $directory = param ('directory'); 
$directory = uri_unescape ($directory); 

my @contents;
readDir($directory);


foreach (@contents) {
  print "$_\n";
}

#------------------------------------------------------------------------
sub readDir(){
 my $dir = shift;
    opendir(DIR, $dir) or die $!;
    while (my $file = readdir(DIR)) {
  next if ($file =~ m/^\./);
  if(-d $dir.$file)
  {
   #print $dir.$file. " ----- DIR\n";
   readDir($dir.$file);
  }
  push @contents, ($dir . $file);
    }
    closedir(DIR);
}

I've tried to make it recursive. I need to have all the files of all of the directories and subdirectories, with the full path, so that i can open the files in the future.

But my output only returns the files in the current directory and the files in the first directory that it finds. If i have 3 folders inside the directory it only shows the first one.

Ex. of cmd call:

"perl readDir.pl directory=C:/PerlTest/"

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遇见了你 2024-10-16 07:46:36

避免重新发明轮子,使用 CPAN。

use Path::Class::Iterator;
my $it = Path::Class::Iterator->new(
        root => $dir,
        breadth_first => 0
);
until ($it->done) {
        my $f = $it->next;
        push @contents, $f;
}

确保您不会让人们将 $dir 设置为会让他们查看您不希望他们查看的位置的内容。

Avoid wheel reinvention, use CPAN.

use Path::Class::Iterator;
my $it = Path::Class::Iterator->new(
        root => $dir,
        breadth_first => 0
);
until ($it->done) {
        my $f = $it->next;
        push @contents, $f;
}

Make sure that you don't let people set $dir to something that will let them look somewhere you don't want them to look.

你丑哭了我 2024-10-16 07:46:36

您的问题是目录句柄 DIR 的范围。 DIR 具有全局作用域,因此对 readDir 的每个递归调用都使用相同的 DIR;因此,当您 closdir(DIR) 并返回到调用者时,调用者会对关闭的目录句柄执行 readdir 操作,然后一切都会停止。解决方案是使用本地目录句柄:

sub readDir {
    my ($dir) = @_;
    opendir(my $dh, $dir) or die $!;
    while(my $file = readdir($dh)) {
        next if($file eq '.' || $file eq '..');
        my $path = $dir . '/' . $file;
        if(-d $path) {
            readDir($path);
        }
        push(@contents, $path);
    }
    closedir($dh);
}

另请注意,如果 (a) 它不在 $directory 末尾或 (b) 在每个递归调用中,您将丢失目录分隔符。 AFAIK,斜杠将在 Windows 上内部转换为反斜杠,但无论如何你可能想使用 CPAN 的路径修改模块(我只关心 Unix 系统,所以我没有任何建议)。

我还建议您将对 @contents 的引用传递给 readDir 而不是将其保留为全局变量,这样可以减少错误和混乱。并且不要在 sub 定义上使用括号,除非您确切知道它们的用途和用途。对 $directory 进行一些健全性检查和清理也是一个好主意。

Your problem is the scope of the directory handle DIR. DIR has global scope so each recursive call to readDir is using the same DIR; so, when you closdir(DIR) and return to the caller, the caller does a readdir on a closed directory handle and everything stops. The solution is to use a local directory handle:

sub readDir {
    my ($dir) = @_;
    opendir(my $dh, $dir) or die $!;
    while(my $file = readdir($dh)) {
        next if($file eq '.' || $file eq '..');
        my $path = $dir . '/' . $file;
        if(-d $path) {
            readDir($path);
        }
        push(@contents, $path);
    }
    closedir($dh);
}

Also notice that you would be missing a directory separator if (a) it wasn't at the end of $directory or (b) on every recursive call. AFAIK, slashes will be internally converted to backslashes on Windows but you might want to use a path mangling module from CPAN anyway (I only care about Unix systems so I don't have any recommendations).

I'd also recommend that you pass a reference to @contents to readDir rather than leaving it as a global variable, fewer errors and less confusion that way. And don't use parentheses on sub definitions unless you know exactly what they do and what they're for. Some sanity checking and scrubbing on $directory would be a good idea as well.

梦幻的心爱 2024-10-16 07:46:36

有许多模块可用于递归列出目录中的文件。

我最喜欢的是 File::Find::Rule

    use strict ;
    use Data::Dumper ;
    use File::Find::Rule ;
    my $dir = shift ;   # get directory from command line

    my @files = File::Find::Rule->in( $dir );
    print Dumper( \@files ) ;

它将文件列表发送到数组中(您的程序正在执行此操作)。

$VAR1 = [
      'testdir',
      'testdir/file1.txt',
      'testdir/file2.txt',
      'testdir/subdir',
      'testdir/subdir/file3.txt'
    ];

还有很多其他选项,例如仅列出具有特定名称的文件。或者您可以将其设置为迭代器,如 中所述如何使用 File::Find

如何我在 Perl 中使用 File::Find?

如果您想坚持使用 Perl Core 附带的模块,请查看 File::Find。

There are many modules that are available for recursively listing files in a directory.

My favourite is File::Find::Rule

    use strict ;
    use Data::Dumper ;
    use File::Find::Rule ;
    my $dir = shift ;   # get directory from command line

    my @files = File::Find::Rule->in( $dir );
    print Dumper( \@files ) ;

Which sends a list of files into an array ( which your program was doing).

$VAR1 = [
      'testdir',
      'testdir/file1.txt',
      'testdir/file2.txt',
      'testdir/subdir',
      'testdir/subdir/file3.txt'
    ];

There a loads of other options, like only listing files with particular names. Or you can set it up as an iterator, which is described in How can I use File::Find

How can I use File::Find in Perl?

If you want to stick to modules that come with Perl Core, have a look at File::Find.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文