【问题标题】:What's that best way to move through directories?浏览目录的最佳方式是什么?
【发布时间】:2010-02-11 08:33:35
【问题描述】:

下面的两个例子都可以,还是第二个例子不好?

案例1:留在顶层目录,使用catdir访问子目录

#!/usr/bin/env perl
use warnings; use strict;

my $dir = 'my_dir_with_subdir';
my ( $count, $dh );

use File::Spec::Functions;
$count = 0;

opendir $dh, $dir or die $!;
while ( defined( my $file = readdir $dh ) ) {
    next if $file =~ /^\.{1,2}$/;
    my $sub_dir = catdir $dir, $file;
    if ( -d $sub_dir ) {
        opendir my $dh, $sub_dir or die $!;
        while ( defined( my $file = readdir $dh ) ) {
            next if $file =~ /^\.{1,2}$/;
            $count++;
        }
        closedir $dh or die $!;
    }
    else {
        $count++;
    }
}

closedir $dh or die $!;
print "$count\n";

案例2:切换到子目录,退出前恢复顶层目录

use Cwd;
my $old = cwd;
$count = 0;
opendir $dh, $dir or die $!;
chdir $dir or die $!;
while ( defined( my $file = readdir $dh ) ) {
    next if $file =~ /^\.{1,2}$/;
    if ( -d $file ) {
        opendir my $dh, $file or die $!;
        chdir $file or die $!;
        while ( defined( my $file = readdir $dh ) ) {
            next if $file =~ /^\.{1,2}$/;
            $count++;
        }
        closedir $dh or die $!;
        chdir $dir;
    }
    else {
        $count++;
    }
}
closedir $dh or die $!;
chdir $old or die $!;
print "$count\n";

【问题讨论】:

  • 不要隐藏你的主要问题!你的读者不应该在混合在一起的两段代码之间做diff
  • 它并没有直接解决你的问题,但是 Higher Order Perl 是一本很棒的书 (hop.perl.plover.com)。第一章使用目录遍历作为递归和回调的有用案例研究。
  • 这一章我会看的,不过如果我没记错的话,这本书的水平对我来说太高了。

标签: perl chdir cwd


【解决方案1】:

你的问题是你应该切换到你正在经历的目录还是留在顶级目录。

答案是:视情况而定。

例如,考虑File::Find。默认行为是确实更改目录。但是,该模块还提供了一个no_chdir 选项以防万一。

在您的示例中,File::Find 可能不合适,因为您不想递归所有子目录,而只想递归一个。这是一个基于File::Slurp::read_dir 的脚本变体。

#!/usr/bin/perl

use strict; use warnings;

use File::Slurp;
use File::Spec::Functions qw( catfile );

my ($dir) = @ARGV;

my $contents = read_dir $dir;
my $count = 0;

for my $entry ( @$contents ) {
    my $path = catfile $dir, $entry;
    -f $path and ++ $count and next;
    -d _ and $count += () = read_dir $path;
}

print "$count\n";

【讨论】:

    【解决方案2】:

    对于您的示例,最好更改为子目录,并且不要在最后更改回原始目录。那是因为每个进程都有自己的“当前目录”,所以你的 perl 脚本正在改变它自己的当前目录这一事实并不意味着 shell 的当前目录被改变了;保持不变。

    如果这是更大脚本的一部分,那就不同了;我的一般偏好是不更改目录,只是为了减少对脚本中任何位置当前目录的混淆。

    【讨论】:

      【解决方案3】:

      使用 File::Find,就像你已经建议的那样:)

      使用模块来解决此类问题几乎总是比使用自己的模块更好,除非你真的想了解walking dirs...

      【讨论】:

      • 我会使用 Path::Class 而不是 File::Find。它有一个更好的 API。
      • 取决于您来自哪里。如果你习惯了 unix 的 find 命令,File::Find 会更熟悉一点。
      • @David Dorward: Path::ClassFile::Find 不要做同样的事情。
      • @Shnan: dir($input)->recurse(callback => sub …);
      • @David Dorward:我的立场是正确的。但是请注意,s/Shnan/Sinan/
      猜你喜欢
      • 1970-01-01
      • 2011-07-30
      • 1970-01-01
      • 2011-06-16
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多