2013-04-05 66 views
1

我写了一些脚本,递归地打印目录的内容。但它会为每个文件夹打印警告。如何解决这个问题?目录树警告

样品夹:

dev的#坎德拉/ TMP /测试
dev的#LS -p -R
TEST2/
testfile的
testfile2

./test2:
testfile3
testfile4

我的代码:

#!/usr/bin/perl 

use strict; 
use warnings; 

browseDir('/tmp/test'); 

sub browseDir { 
    my $path = shift; 
    opendir(my $dir, $path); 
    while (readdir($dir)) { 
     next if /^\.{1,2}$/; 
     if (-d "$path/$_") { 
      browseDir("$path/$_"); 
     } 
     print "$path/$_\n"; 
    } 
    closedir($dir); 
} 

和输出:

开发#perl的/tmp/cotest.pl
的/ tmp /测试/测试2/testfile3
的/ tmp /测试/测试2/testfile4
使用未初始化值$ _的在 级联(。)或串在/tmp/cotest.pl线16
/TMP /测试/
/TMP /测试/ testfile的
/TMP /测试/ testfile2

+0

'文件:: Spec' < - 这个模块有'no_upwards()'FUNC隐藏像'.'或'..'所有目录。例如:'@paths =文件::规格 - > no_upwards(@paths);' – gaussblurinc 2013-04-05 13:01:53

+0

你应该把一个'使用5.012;'在你的程序,因为你用'而(READDIR($ DIR)){...}'这在早期版本中不起作用。 – 2013-04-05 14:59:29

回答

1

您可能试试这个代码:

#!/usr/bin/perl 

    use strict; 
    use warnings; 

    browseDir('/tmp'); 

    sub browseDir { 
     my $path = shift; 
     opendir(my $dir, $path); 
     while (readdir($dir)) { 
      next if /^\.{1,2}$/; 
      print "$path/$_\n"; 
      if (-d "$path/$_") { 
       browseDir("$path/$_"); 
      } 
     } 
     closedir($dir); 
    } 

如果你有这个错误,那是因为你在使用变量$ _之前调用browseDir()。

+0

谢谢,它的工作原理。另外如果我不使用$ _变量没有警告打印。 'while(my $ s = readdir($ dir)){...}' – Suic 2013-04-05 13:02:34

+0

OP是否改变了他的代码?我无法找到你和他的任何区别。 – ikegami 2013-04-05 13:28:58

+0

'打印 “$ PATH/$ _ \ n”;'上升 – Suic 2013-04-05 13:35:35

1

你放在$_值调用browseDir之前,你希望它的价值是调用browseDir(一个合理的预期)后存在,但browseDir修改该变量。

只需添加local $_;browseDir以确保任何改变它的子退出之前撤消。


无关你的问题,这里有其他的三个问题:

  • 没有最起码的错误检查!
  • 您可能会用完目录句柄将导航深层目录。
  • 您过滤掉了文件".\n""..\n"

修复:

#!/usr/bin/perl 

use strict; 
use warnings; 

browseDir('/tmp/test'); 

sub browseDir { 
    my $path = shift; 

    opendir(my $dh, $path) or die $!; 
    my @files = readdir($dh); 
    closedir($dh); 

    for (@files) { 
     next if /^\.{1,2}z/; 
     if (-d "$path/$_") { 
      browseDir("$path/$_"); 
     } 

     print "$path/$_\n"; 
    } 
} 

最后,为什么不使用你的模块状File::Find::Rule

use File::Find::Rule qw(); 
print "$_\n" for File::Find::Rule->in('/tmp'); 

注:5之前。12,while (readir($dh))必须写入while (defined($_ = readdir($dh)))

+0

感谢您的意见,我永远不会使用$ _了^ _^ – Suic 2013-04-05 13:32:46

+0

其实'而(READDIR($ DIR)){...}'被转换为'而(定义($ _ = READDIR($ DIR) )){...}从[5.12]开始(http://perldoc.perl.org/perlfunc.html#readdir-DIRHANDLE)。 [提交](http://perl5.git.perl.org/perl.git/commit/114c60ecb1f775ef1deb4fdc8fb8e3a6f343d13d)不幸的是,这从来没有成为一个三角洲。 – 2013-04-05 15:11:29

+0

@Brad Gilbert,真的哦!那么问题是缺少'$ _'的本地化。递归调用是破坏'$ _'中父对象的值。更新了答案。 – ikegami 2013-04-05 17:24:45

1

为什么不使用File::Find模块?自Perl 5.x以来,它几乎包含在Perl的所有发行版中。这不是我最喜欢的模块,因为它的工作方式很混乱,但它做得很好。

可以定义你想要做的是什么wanted子程序,并过滤掉你不想要的东西。在这种情况下,您几乎可以打印所有内容,因此所有wanted都会打印出找到的内容。

File::Find中,文件的名称保存在$File::Find::name中,该文件的目录在$File::Find::dir中。 $_是文件本身,可用于测试。

这里有你想要的一个基本途径:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 

find (\&wanted, $directory); 

sub wanted { 
    say $File::Find::Name; 
} 

我宁愿把我的wanted功能在我find子程序,所以他们在一起。这相当于以上内容:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 

find ( 
    sub { 
     say $File::Find::Name 
    }, 
    $directory, 
); 

好的编程说不打印在子程序中。相反,您应该使用子例程来存储和返回数据。不幸的是,find根本没有返回任何东西。你必须使用一个全球阵列捕捉到的文件列表,后来把它们打印出来:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 
my @directory_list; 

find ( 
    sub { 
     push @directory_list, $File::Find::Name 
    }, $directory); 

for my $file (@directory_list) { 
    say $file; 
} 

或者,如果你喜欢一个独立的wanted子程序:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 
my @directory_list; 

find (\&wanted, $directory); 
sub wanted { 
    push @directory_list, $File::Find::Name; 
} 

for my $file (@directory_list) { 
    say $file; 
} 

事实证明我的通缉子程序取决于数组的子程序困扰我这就是为什么我喜欢嵌入我的find调用内部的wanted子程序,这不是地方。

一两件事你可以做的是使用你的子程序来筛选出你想要的东西。比方说,你在JPG文件是唯一感兴趣的是:

use strict; 
use warnings; 
use feature qw(say); 

use File::Find; 

my $directory = `/tmp/test`; 
my @directory_list; 

find (\&wanted, $directory); 
sub wanted { 
    next unless /\.jpg$/i; #Skip everything that doesn't have .jpg suffix 
    push @directory_list, $File::Find::Name; 
} 

for my $file (@directory_list) { 
    say $file; 
} 

注意通缉子程序如何做之前我把它放到我@directory_list阵列我不希望任何文件next。同样,我更喜欢嵌入:

find (sub { 
    next unless /\.jpg$/i; #Skip everything that doesn't have .jpg suffix 
    push @directory_list, $File::Find::Name; 
} 

我知道这是不是正是你问什么,但我只是想让你知道的Find::File模块并为您介绍Perl模块(如果你没有已经了解它们)可以为Perl添加很多功能。