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

Hello all,
I am still learning, and I have managed to create a script that will list the path to the file, the name of the file, and the size of the file in the format: path,filename,size. Now I need to do it not only for the current directory but for all subdirectories as well. However that is out of my skills for now. Can anybody advice?
Thank you for your time.
Here is the script I have so far:
#!/usr/bin/perl -w #!C:\Perl\bin\perl -w my $directory='/data/input'; my $size=0; my $file; opendir(DIRHANDLE, $directory) or die "couldn't open $directory : $!\n +"; my@files = grep(!/^\.\.?$/,readdir(DIRHANDLE)); foreach $file (@files) { $size=(-s "$directory/$file"); print "$directory,$file,$size"; print "\n"; } closedir(DIRHANDLE);

Replies are listed 'Best First'.
Re: go through directories recursively
by Fletch (Bishop) on Feb 03, 2004 at 16:41 UTC
    • perldoc File::Find
    • perldoc find2perl

    This concludes today's RTFM on walking the filesystem. Tune in tomorrow, when Vivian confronts Alberto with the shocking news that his inode was actually fathered by Dirk.

Re: go through directories recursively
by broquaint (Abbot) on Feb 03, 2004 at 16:45 UTC
    Use one of the File::Find-esque modules e.g
    use File::Basename qw/ dirname basename /; use File::Find::Rule; my $rule = rule( file => start => '/data/input' ); while(my $path = $rule->match) { printf "%s,%s,%s\n", dirname($path), basename($path), -s $path; }
    Update: or if you don't mind slurping the whole list
    ## do same 'use's as above printf "%s,%s,%s\n", dirname($_), basename($_), -s $_ for find( file => in => '/data/input' );
    HTH

    _________
    broquaint

      hello broquaint,

      Thank you for your suggestion, unfortunately I don't have package File::Find. When I run your script, it gives me this error:
      "go3.pl" [New file] 5 lines, 230 characters normal@firestarter:/data/input> perl go3.pl Can't locate File/Find/Rule.pm in @INC (@INC contains: /usr/perl5/5.00 +503/sun4-solaris /usr/perl5/5.00503 /usr/perl5/site_perl/5.005/sun4-s +olaris /usr/perl5/site_perl/5.005 .) at go3.pl line 2. BEGIN failed--compilation aborted at go3.pl line 2.
        Then you need to install the module, and fortunately I've covered this very subject before at Re: Re: Re: Find file name. One thing I forgot to mention there was that you'll also need to install Number::Compare and Text::Glob, if you haven't already, to fulfil FFR's dependencies.
        HTH

        _________
        broquaint

        danield, it's worth persevering with the File::Find::Rule install. So much easier than the opendir route. If you have root, it's no harder than:

        perl -MCPAN -e 'install File::Find::Rule';
        -- vek --
Re: go through directories recursively
by pelagic (Priest) on Feb 03, 2004 at 16:40 UTC
    I'd like to point you to a posting I made earlier today for a similar problem: (see 326175)

    This code keeps a array of directories and works through them sequentially. Finding a dir somewhere adds it to that array.
    pelagic

      I did check your suggestion, and the code now looks like this:
      #!/usr/bin/perl -w #!C:\Perl\bin\perl -w my $directory='/data/input/data.01.29.2004-15:34:19/content'; my $size=0; my $file; #opendir(DIRHANDLE, $directory) or die "couldn't open $directory : $!\ +n"; #my@files = grep(!/^\.\.?$/,readdir(DIRHANDLE)); push(@dirs,$directory); # add an element to an array foreach $dir (@dirs) # loop through the elements of an array { opendir(DIR,"$dir") || die "opendir $dir failed"; my@list = grep(!/^\.\.?$/,readdir(DIR)); closedir(DIR); foreach $file (@list) { $size=(-s "$dir/$file"); print "$directory,$file,$size"; print "\n"; } }; #closedir(DIRHANDLE);

      However it still does not do what I want. The script now gives a list of subdirectories of 'content' directory. Each subdirectory however contains files I am interested in. Example:

      /data/input/data.01.29.2004-15:34:19/content/1/file001.txt
      ..
      /data/input/data.01.29.2004-15:34:19/content/1/file100.txt
      /data/input/data.01.29.2004-15:34:19/content/2/file001.txt
      ..
      /data/input/data.01.29.2004-15:34:19/content/2/file100.txt
      ..

      What I get is:

      /data/input/data.01.29.2004-15:34:19/content,1,8192
      /data/input/data.01.29.2004-15:34:19/content,2,8192
        ok, you dropped an important part and you had a couple of typos also. Like that it works:
        #!/usr/bin/perl -w #!C:\Perl\bin\perl -w my $directory='C:\dev\perl'; my $size=0; my $file; #opendir(DIRHANDLE, $directory) or die "couldn't open $directory : $!\ +n"; #my@files = grep(!/^\.\.?$/,readdir(DIRHANDLE)); push(@dirs,$directory); # add INITIAL directory to an array foreach $dir (@dirs) # loop through the elements of an array { opendir(DIR,"$dir") || die "opendir $dir failed"; my@list = grep(!/^\.\.?$/,readdir(DIR)); closedir(DIR); foreach $file (@list) { if (-d "$dir/$file") { push(@dirs, "$directory/$file"); # if this is a dir ad +d it to an array } if (-f "$dir/$file") { # only if it a file do your +size stuff $size=(-s "$dir/$file"); print "$dir,$file,$size"; print "\n"; } } }; #closedir(DIRHANDLE);

        see comments in code ...
        pelagic
Re: go through directories recursively
by dominix (Deacon) on Feb 04, 2004 at 07:39 UTC
Re: go through directories recursively
by graff (Chancellor) on Feb 04, 2004 at 13:50 UTC
    Oh, definitely follow up on paco's ground-breaking node -- you haven't been at perlmonks till you've been there. I'm serious.

    But I'll add one more option (shameless plug): An alternative to File::Find -- I know, I know... lots of monks think it's dirty somehow to use an existing utility program in a subprocess to do something that a perl module can do. But "find" is available on all unix systems (including MacOSX, of course), it's easy to get an MS-windows port (find.exe) from numerous great sources, and (ahem) it's just faster and easier in all respects when compared to File::Find. Just my $0.02...