目录树警告

时间:2013-04-05 12:44:25

标签: perl

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

示例文件夹:

  

dev#cd / tmp / test
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);
}

和输出:

  

dev #perl /tmp/cotest.pl
/ tmp / test / test2 / testfile3
  / tmp / test / test2 / testfile4
使用未初始化的值$ _ in   连接(。)或字符串在/tmp/cotest.pl第16行。
/ tmp / test /
  的/ tmp /测试/ testfile的
/ TMP /测试/ testfile2

3 个答案:

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

答案 1 :(得分: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)))

答案 2 :(得分: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;
}

我想要的子程序取决于一个不在子程序本地的数组这个事实困扰我,这就是为什么我更喜欢在我的wanted调用中嵌入find子程序。

您可以做的一件事是使用您的子程序过滤掉您想要的内容。假设您只对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;
}

注意想要的子例程在我将其推入next数组之前对我不想要的任何文件执行@directory_list的过程。再次,我更喜欢嵌入:

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

我知道这不完全是您的要求,但我只是想让您了解Find::File模块,并向您介绍可以添加的Perl模块(如果您还不知道它们) Perl的许多功能。