http://qs321.pair.com?node_id=606763

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

What is the quickest way to find number of files in a directory? I don't want to touch or analyse them, just to count the number.

Thanks,
Jon
  • Comment on quickest way to find number of files in a directory?

Replies are listed 'Best First'.
Re: quickest way to find number of files in a directory?
by kyle (Abbot) on Mar 27, 2007 at 15:10 UTC

    I haven't benchmarked this (with Benchmark) or anything, but a quick opendir/readdir would get it done:

    my $directory_name = shift || '.'; opendir my $dh, $directory_name or die "Can't opendir '$directory_name': $!"; my $file_count = scalar grep { -f "$directory_name/$_" } readdir $dh; closedir $dh or die "Can't closedir: $!";

    It's bigger and more complicated than a glob-based solution, but you get nice error messages in case there's problems.

    If you're interested in all directory entries (i.e., subdirectories and not just files), you can make the grep match { !m{ \A \.\.? \z}x } instead (so it still skips "." and "..").

    Updated to fix a problem helpfully pointed out by Corion. The -f needs to have the directory named explicitly in case it's not the current directory.

      ++ to you. That's the way to go.

      I like let handles close automatically on block exit (where feasible) and since this snippet fits naturally in a sub, I'd do this:

      sub files_in_dir { my $dir = shift || '.'; opendir my $dh, $dir or croak "opendir '$dir' - $!"; grep { -f } readdir $dh; }

      It produces the number of files if called in scalar context and the list of filenames if called in list context.

      A word spoken in Mind will reach its own level, in the objective world, by its own weight
Re: quickest way to find number of files in a directory?
by davorg (Chancellor) on Mar 27, 2007 at 15:03 UTC

      Nit-picking: the dot files (like ".bashrc") are not counted when using the glob.

        That depends on your shells. At least under bash, you can use glob() to grab dot files, for example:
          print "$_\n" for grep{ -f } glob(".*");
        
        Or probably if you want to grab both dot and non-dot files:
          print "$_\n" for grep{ -f } glob("{*,}.*");
        
        Regards,
        Xicheng
        is it efficient with more than 100 000 files in the directory ? if I well understand the code, each inode is loaded in memory... so do you know another mean to get this count, without need of a huge memory ?
      That also fails if $dir contains spaces or other glob meta characters.
      That works very nicely, thank you.
        Some people use whitespaces in paths. Try: my @files = <'$dir/*'>;
      Thanks a lot, that works great. Does anybody know if it's possible to include variables in the file handle? For example, if I want all the .pl files starting with 'blabla' is it possible to do something like this: my $prename = 'blabla'; my @files = <$prename*.pl> my $count = @files It works with just <*.pl> but I can't get the variable to work.
Re: quickest way to find number of files in a directory?
by johngg (Canon) on Mar 27, 2007 at 15:05 UTC
    You could try this. It excludes the '.' and '..' links

    $ perl -le ' opendir D, q{dirname} or die $!; print scalar grep { ! m{^\.\.?$} } readdir D;' 123 $

    Cheers,

    JohnGG

Re: quickest way to find number of files in a directory?
by izut (Chaplain) on Mar 28, 2007 at 00:16 UTC

    Depending on the amount of the files you're talking about, maybe File::Find::Rule fit your needs:

    use strict; use warnings; use File::Find::Rule; my @files = File::Find::Rule->file()->in('/my/path'); print scalar @files, $/;

    Igor 'izut' Sutton
    your code, your rules.

      Are we talking quick, as in coding/thinking time?
      ` ls -a1 | wc -l`
      Well -2 entries for . and ..
      Are we talking quick, as in coding/thinking time? ` ls -a1 | wc -l`

        Well, you could also do `find /tmp -type f | wc -l`, but I think that backticks are evil. Ah, and we also could free our minds from Perl and write some nasty bash script code :-P.

        Igor 'izut' Sutton
        your code, your rules.

Re: quickest way to find number of files in a directory?
by trizen (Hermit) on Dec 11, 2011 at 02:50 UTC
    Here is a pretty fast script that finds the number of files and directories in a given path.
    #!/usr/bin/perl use strict; my $f; # number of files my $d; # number of dirs sub count_files { my ($ref) = @_; foreach my $dir (@$ref) { $dir = readlink $dir and chop $dir if -l $dir; # read link next unless opendir(my $dir_h, $dir); # open dir o +r next my @dirs; while (defined(my $file = readdir $dir_h)) { if ($file eq '.' or $file eq '..') { next; } if (-d "$dir/$file") { ++$d; # counting d +irs push @dirs, "$dir/$file"; } elsif(-f _){ ++$f; # counting f +iles } } closedir $dir_h; count_files(\@dirs); } [$f, $d]; } foreach my $arg (@ARGV) { my @dir = -d $arg ? $arg : next; ($f, $d) = (0, 0); print "$arg\nFiles\t: $$_[0]\nDirs\t: $$_[1]\n" for count_files(\@ +dir); }

    Usage:
    $ time perl test.pl /tmp/ /usr/bin/ /media/ /tmp/ Files : 844 Dirs : 15 /usr/bin/ Files : 1564 Dirs : 3 /media/ Files : 10031 Dirs : 689 real 0m0.111s user 0m0.030s sys 0m0.070s
      Dear trizen, Thank you very much. I have checked around and so far I can conclude that Your Perl script works correctly and efficiently. Especially, it runs rapidly.
Re: quickest way to find number of files in a directory?
by pvaldes (Chaplain) on Jul 02, 2012 at 17:51 UTC

    The quickest way...

    This sounds to "inode count" to me...

    maybe use Inline C => ... and point your arrows to stat and the inode table?.

    I agree, quickest and simplest are not always the same thing... with great speed comes great responsability... and fantastic headaches too