Enric Agud Pique Enric Agud Pique - 5 months ago 29
Perl Question

count number of files in a folder with perl

I would like to count the number of files inside a folder with perl. With the following code I can list them, but i don't know how to count them in perl. Any help?

$dir = "/home/Enric/gfs-0.5.2016061400";
opendir(DIR, "$dir");
@FILES = grep { /gfs./ } readdir(DIR);
foreach $file (@FILES) {
print $file, "\n";
}
closedir(DIR);

Answer

If you want to just count them, once you have a directory open for reading you can manipulate context on readdir so that it returns the list of all entries, and then assign that to a scalar. This gives you the length of the list, ie. the number of entries

opendir my $dh, $dir;
my $num_entries = () = readdir($dh);

The construct = () = goes under the name of goatse operator, see it in perlsecret. There are clearer ways, of course, as below.

If you want to count certain kinds of files, pass the file list through grep, filtering what you need. Since grep imposes the list context on its input readdir returns the list of all files, and after filtering grep itself returns a list. When you then assign that to a scalar you get the count. For example, for all regular files and /gfs./ files

use warnings;
use strict;

my $dir = '/home/Enric/gfs-0.5.2016061400';
opendir my $dh, $dir  or die "Can't open $dir: $!";

my $num_files =  grep { -f "$dir/$_" } readdir($dh);
my $num_gfs   =  grep { /gfs./ } readdir($dh);

Note that readdir returns the bare filename, without any path. So for most of what is normally done with files we need to prepend it with the path (unless you first chdir to that directory). This is what is done in the grep block above so that the -ffile test (-X) has the correct filename.

If you can make use of the file list itself, get that and then use scalar on the array to get the count

# Get the file list, then its length
my @files_gfs = map { "$dir/$_" } grep { /gfs./ } readdir($dh);
my $num_gfs = scalar @files_gfs;

Here map builds the full path for each file. If you don't need the path drop map { }. Or, for count

my $num_gfs = @files_gfs;

Since you are directly assigning an array to a scalar you don't need the explicit scalar.

If you are processing files as you read, count as you go.

my $cnt_gfs = 0;
while (my $filename = readdir($dh)) {
    $cnt_gfs++ if $filename ~= /gfs./;
    # Process $filename as needed
}