【问题标题】:How do I get a listing of only plain files in a directory using Perl?如何使用 Perl 获取目录中仅普通文件的列表?
【发布时间】:2010-05-12 17:22:48
【问题描述】:

我正在寻找一种在 Perl 中列出目录的普通文件的方法。只有文件,没有目录。

【问题讨论】:

    标签: perl


    【解决方案1】:

    您需要将opendirreaddirclosedir函数与-f文件测试运算符结合使用:

    opendir(my $dh, $some_dir) || die $!;
    while(my $f = readdir $dh) {
        next unless (-f "$some_dir/$f");
        print "$some_dir/$f\n";
    }
    closedir $dh;
    

    【讨论】:

    • 在我看来,File::Find 是更通用、更好的答案。
    • 如果您不想对整棵树进行深度优先搜索,File::Find 不是您要寻找的机器人。
    【解决方案2】:

    列出目录中所有文件的另一种方法是使用 CPAN 模块 File::Slurp 中的 read_dir 函数:

    use strict;
    use warnings;
    use File::Slurp qw(read_dir);
    
    my $dir = './';
    my @files = grep { -f } read_dir($dir);
    

    它会为您执行 opendir 检查。请记住,它包括任何“隐藏”文件(以点开头的文件)。这不会递归地列出指定目录的子目录中的文件。

    【讨论】:

      【解决方案3】:

      您可以使用文件测试“运算符”(实际上是一个函数)来检查您想要的文件类型。

      在您想要扫描当前目录的简单情况下,使用带有 grep 的文件 glob:

      my @files = grep -f, <*>;
      

      否则,您可以使用目录句柄:

      opendir my $dh, $dirpath;
      
      my @files = grep -f, readdir( $dh );
      
      closedir $dh;
      

      请参阅opendirreaddirclosedir-Xgrep

      【讨论】:

        【解决方案4】:

        使用File::Find。它是一个核心模块。

        use File::Find;
        find(\&wanted, @directories_to_search);
        sub wanted 
        { 
           my $file = shift;
           return unless (-f $file);
           #process file
        }
        

        【讨论】:

        • 这是最好的答案,因为它使用了已经编写和测试过的库。 File::Find 在核心 Perl 中,所以你不需要安装任何东西。
        • 请记住,这将递归列出指定目录的所有子目录中的所有文件。
        【解决方案5】:

        您需要readdir 运算符。

        例如:

        #! /usr/bin/perl
        
        use warnings;
        use strict;
        
        my $dir = "/tmp/foo";
        opendir my $dh, $dir
          or die "$0: opendir: $!";
        
        while (defined(my $name = readdir $dh)) {
          next unless -f "$dir/$name";
          print "$name\n";
        }
        

        运行它:

        $ ls -F /tmp/foo
        A B C D/
        
        $ ./prog.pl
        b
        C
        一个

        如您所见,名称是按照它们物理存储在文件系统上的顺序出现的,不一定是排序的。

        要走快速而肮脏的路线,您还可以使用 glob 运算符,如

        print map { s!^.*/!!; "$_\n" }
              grep !-d $_ =>
              </tmp/foo/*>;
        

        请注意,您必须从结果中删除目录,并且 glob 运算符不会返回名称以点开头的文件。

        【讨论】:

          【解决方案6】:

          来自 CPAN 的File::Find::Rule 让这一切变得微不足道:

          use File::Find::Rule;
          my @files = File::Find::Rule->file->in( $directory );
          

          这将查找给定目录或其任何子目录中的所有文件。我推荐这个,因为它结合了极大的灵活性和简单性。

          【讨论】:

          • 这个可以用来查找路径中的所有文件,例如:a/**/**/b/**/c.txt
          • 当然!您只需要在文件之后添加一个 name() 调用 - 但请务必使用 Unix 样式的通配符(单星号)。如果你愿意,你也可以在那里使用正则表达式:name('.*something[A-Z].*\.foo')。所以你会说 File::Find::Rule->file->name('a/*/*/b/*/c.txt')->in($directory) 来找到你的示例文件。跨度>
          猜你喜欢
          • 1970-01-01
          • 2020-09-11
          • 1970-01-01
          • 2010-09-17
          • 1970-01-01
          • 2011-10-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多