【问题标题】:Getting the names and sizes of all the files in sub-directories using PERL使用 PERL 获取子目录中所有文件的名称和大小
【发布时间】:2018-10-16 09:44:38
【问题描述】:

我编写了一个例程来读取两个文件夹及其所有子文件夹中包含的文件的所有名称和大小。根文件夹名称在命令行参数中提供,每个文件夹都在 for 循环中处理,详细信息将输出到两个文件夹中的每一个的单独文件中。但我发现只有两个根文件夹中文件的文件名/大小被输出,我无法更改到子文件夹并重复该过程,因此子目录中的文件被忽略。调试跟踪显示 chdir 命令从未执行,因此我的评估有问题,但我看不到它是什么。 代码是这样的

#!/usr/bin/perl
#!/usr/local/bin/perl

use strict;
use warnings;

my $dir = $ARGV[0];
opendir(DIR, $dir) or die "Could not open directory '$dir' $!";
my @subdirs = readdir(DIR) or die "Unable to read directory '$dir': $!";

for (my $loopcount = 1; $loopcount < 3; $loopcount = $loopcount + 1) {
    my $filename = 'FileSize_'.$dir.'.txt';
    open (my $fh, '>', $filename) or die "Could not open file '$filename' $!";      
    for my $subdir (sort @subdirs) {
        unless (-d $subdir) {
            # Ignore Sub-Directories in this inner loop
            # only process files
            # print the file name and file size to the output file
            print "Processing files\n";
            my $size = -s "$dir/$subdir";
            print $fh "$subdir"," ","$size\n";
        }
        elsif (-s "$dir/$subdir") {
        # We are here because the entry is a sub-folder and not a file
        # if this sub-folder is non-zero size, i.e has files then
        # change to this directory and repeat the outer for loop
            chdir $subdir;
            print "Changing to directory $subdir\n";
            print "Processing Files in $subdir\n";
        };
    }
    # We have now processed all the files in First Folder and all it's subdirecorries
    # Now assign the second root directory to the $dir variable and repeat the loop
    print "Start For Next Directory\n";
    $dir = $ARGV[1];
    opendir(DIR, $dir) or die "Could not open directory '$dir' $!";
    @subdirs = readdir(DIR) or die "Unable to read directory '$dir': $!";;
}
exit 0;

命令行调用是“perl FileComp.pl DiskImage DiskImage1” 但只输出根 DiskImage 和 DiskImage1 文件夹中文件的文件名和文件大小,忽略子文件夹中的所有文件。 永远不会满足更改为“elseif”条件的代码并且永远不会执行代码,因此那里存在错误。 提前感谢您的任何建议。

【问题讨论】:

标签: perl


【解决方案1】:

此检查很可能总是错误的,因为您正在查看错误的内容。

   unless (-d $subdir) {

$subdir$dir 中的文件或目录的文件名,因此要访问它,您需要使用$dir/$subdir 的完整相对路径,就像您在这里所做的那样:

        my $size = -s "$dir/$subdir";

如果您确实修复了unless 检查,您也会遇到问题,因为在阅读$dir 的内容期间执行chdir 也会导致问题,因此将在看到$dir/$subdir 的后续实例的位置错误。

【讨论】:

    【解决方案2】:

    在不更改目录的情况下执行这样的逻辑要容易得多,但是如果您确实使用 File::chdirFile::pushd 以便在退出该范围时返回到上一个目录。但是,通过使用像 Path::Iterator::Rule 这样处理子目录逻辑的递归迭代器来解决这个问题要容易得多:

    use strict;
    use warnings;
    use Path::Iterator::Rule;
    use Path::Tiny;
    
    my $rule = Path::Iterator::Rule->new->not_directory;
    foreach my $dir (@ARGV) {
        my $fh = path("FileSize_$dir.txt")->openw;
        my $next = $rule->iter($dir);
        while (defined(my $item = $next->())) {
            my $size = -s $item;
            print $fh "$item $size\n";
        }
    }
    

    或者,您可以使用visitor 回调,它会同时传递每个项目的完整路径(用于文件操作)和基本名称:

    my $rule = Path::Iterator::Rule->new->not_directory;
    foreach my $dir (@ARGV) {
        my $fh = path("FileSize_$dir.txt")->openw;
        $rule->all($dir, {visitor => sub {
            my ($path, $basename) = @_;
            my $size = -s $path;
            print $fh "$basename $size\n";
        }});
    }
    

    【讨论】:

    • 嗨,Grinnz - 非常感谢您的帮助 - 在我从 CSPAN 安装 Path::Iterator::Rule 模块后,它就可以工作了!!
    • 是的,一些模块有这样的迭代器,它们有时真的很方便,正是你想要的。作为说明,看到File::pushd 并没有(似乎)完全支持简单的chdir 后退,我有点吃惊;如果我想回到同一个范围内怎么办?可以undef它但是为什么没有方法呢?如果不是这样,那么我希望能够保留pushd-ing,然后使用我的堆栈到chdir 到我去过的地方; popd 之类的。我不认为它会带走简单性。只是一个评论,它是一个很好的功能。
    • 这就是 pushd 在 shell 中的工作方式,但 File::pushd 决定利用 Perl 的动态作用域。从逻辑上讲,我认为如果它试图同时提供范围保护和显式 pushd/popd 堆栈,它会变得混乱。您可以通过在顶层创建一个 @dirs 数组来模拟这一点,然后将 push @dirs, pushd $foo; 然后 pop @dirs; 作为您的 popd,因此对象由该数组而不是词法范围保存。
    • 编辑提到 File::chdir 这是一种较旧但类似动态范围的方法,使用local而不是范围保护。
    • 那里肯定有设计问题,我想这是一个深思熟虑的决定,导致了模块的方式。但它确实感觉它少了一半(可以这么说)——我就是不能回去(除了可怕的undef $obj 来摧毁它);所以只是一个小小的简单的chdir_back 或类似的东西。 (我提到保留堆栈作为另一种选择,但我同意这可能会将事情带到其他地方。)
    猜你喜欢
    • 2013-05-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 2014-05-20
    • 1970-01-01
    • 2014-01-22
    • 1970-01-01
    • 2013-07-23
    相关资源
    最近更新 更多