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

I'm writing a perl script to process files in a directory and it has recursion to process sub directories. However my code stops after first recursion and I can't figure out why it's loosing it's place. It looks like I'm loosing my directory handle but I can't figure out why. Can anyone lend me a hand and educate me on my issue? Here is my sub

sub ScanDir { my($dir) = @_; my ($file); if (substr ($dir,-1) ne "/") { $dir .= "/"; } opendir(DIR, $dir) or die $!; while ($file = readdir(DIR)) { next if ($file =~ m/^\./); $FullName = $dir.$file; if (-d $FullName) { ScanDir($FullName); } else { next unless (-f $FullName); @fdata = stat($FullName); open(FILE, $FullName) or die "Error: Could not open $FullName fo +r MD5 checksum"; binmode(FILE); my $md5sum = $md5->addfile(*FILE)->hexdigest; close FILE; print "$FullName, $fdata[7], $fdata[8], $fdata[9], $md5sum\n" } } closedir(DIR); }

Replies are listed 'Best First'.
Re: Recursion not working
by BrowserUk (Patriarch) on Jul 28, 2012 at 19:19 UTC
    It looks like I'm loosing my directory handle but I can't figure out why.

    DIR is a global filehandle. When you recurse, you re-use that same global directory handle and the previous level's use of it gets over-written.

    You have two options:

    1. Use lexical handles: In place of DIR & FILE use:
      opendir( my $dh, $dir) or die $!; while ($file = readdir( $dh )) ... open( my $fh, $FullName) or die ...
    2. Or localise those global handles: Add the following to the top of your sub
      sub ScanDir { local( DIR, FILE ); ...

    One requires minimum changes; the other is seen as the "Modern" option. Both will work.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: Recursion not working
by tobyink (Canon) on Jul 28, 2012 at 20:56 UTC

    I think you want to be constructing a new Digest::MD5 object for each file, not reusing the same one. Otherwise you'll get a cumulative digest.

    I strongly suggest looking at Path::Class which makes working with files and directories a lot easier, reducing a lot of "boilerplate" code.

    use Digest::MD5 (); use Path::Class (); sub ScanDir { Path::Class::Dir::->new(shift)->recurse(callback => sub { my $file = shift; return if $file->is_dir; my $stat = $file->stat; printf( "%s, %s, %s, %s, %s\n", $file->absolute, $stat->size, $stat->atime, $stat->mtime, Digest::MD5::->new->addfile($file->openr)->hexdigest, ); }) } ScanDir("/tmp");

    Path::Class::Rule is also good fun, though not especially useful for this particular task.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Recursion not working
by BillKSmith (Monsignor) on Jul 28, 2012 at 22:31 UTC

    The module File::Find would do the recursion for you.