icarus wrote:
> what this does: it classifies a file based on its modification date.
> 
> example: xfile1 is dated July 9, 2008.  If it doesn't exist, the
> program creates a
> directory structure 2008/July/09 and places xfile1 there.
> Then it creates a log with the steps done.
> 
> So...in the system the result is 2008/July/09/xfile1
> The log entry looks like "xfile1 => 2008/July/09"
> 
> problem: When I send an INT signal (Control+C) from the keyboard for
> example,
> it exists nicely, it finishes whatever file it needed to finish, and
> it classifies the file
> properly.  However, it misses some entries on the log file.  Out of
> 4,000 files if you INT the program twice or three times it won't write
> about 2 or 3 entries on the log.
> 
> How can I not lose an entry on the log file? if you have other
> suggestions to make this code
> more efficient please let me know. Thanks in advance.
> 
> Code:
> 
> #!/usr/bin/perl
> use warnings;
> use strict;
> use File::Copy;
> use File::Path;
> use File::Find;
> use Time::localtime;
> no warnings 'File::Find';
> 
> 
> my @target_directories = ("/full/path/to/test1", "/full/path/to/
> test2");
> my $files_moved = "test.log";
> my $files_moved_fh;
> my $source_dir_handler;
> my $signal;
> my $list;
> my $condition = 1;
> 
> 
> $| = 1; #flush buffers
> 
> my @months =
> ("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");
> my @all_signals = qw (STOP KILL ABRT QUIT TERM INT TSTP HUP);
> 
> sub signal_handler {
>     $signal = shift;
>     $condition = 0;
> }
> 
> 
> find( { wanted => \&process, no_chdir => 0 }, @target_directories );
> 
> sub process {
> 
>     foreach $list(@all_signals){
>         $SIG{$list} = \&signal_handler;
>     }
> 
>     while ( $condition == 1 ) {
>         foreach my $xdir (@target_directories){
>                       opendir ($source_dir_handler, $xdir) or die $!;
>                       chdir $xdir;
> 
>                       while (defined (my $xfile = readdir 
> ($source_dir_handler))){
> 
>                                       #skip . and .. files and directories
>                                       next if ($xfile =~ m/^\./);  #skip dot 
> files . and ..
>                               next if -d $xfile;
> 
>                               #extract year, month, day when $_ was last 
> modified
>                                       my $calendar = 
> localtime((stat($xfile))[9]);
>                                       my $dd = $calendar->mday;
>                                       my $mm = $calendar->mon;
>                                       my $yyyy = $calendar->year+1900;
>                                       my $dir = $yyyy . '/' . $months[$mm] . 
> '/' . $dd;  #eg 2008/July/
> 9
> 
>                               if (! -d $dir and ! -e $dir ){
>                                               mkpath([$dir], 0, 0750) or die 
> $!;
>                                       move ($xfile, $dir) or die $!;
>                                       open ($files_moved_fh, ">>", 
> $files_moved) or die $!;
>                                       print $files_moved_fh "$xfile => 
> $dir\n";
>                                       close $files_moved_fh;
>                               }
>                               else {
>                                       move ($xfile, $dir) or die $!;
>                                       open ($files_moved_fh, ">>", 
> $files_moved) or die $!;
>                                       print $files_moved_fh "$xfile => 
> $dir\n";
>                                       close $files_moved_fh;
>                               }
> 
>                       }
> 
>               }
>                $condition = 0;
>       }
>  }


You're misunderstanding the way File::Find works and doing all of its work for
it inside process()!

File::Find calls the wanted routine for every file and directory it finds at or
below the paths specified, but you've written process() so that it looks through
the directories again itself.

Because File::Find it meant for traversing entire directory trees, and you're
only interested in the contents of a single directory, I would forget about
using the module.

I can't see straight away why you're missing entries from the log file, but I
suggest you fix the bugs first. The program below should do the trick.

I've used the strftime function from the POSIX module to format the destination
path (it's a standard module so won't need installing) and you may as well call
mkpath whether or not the directory already exists - there's no harm done if it
has nothing to do.

HTH,

Rob



use warnings;
use strict;

use File::Copy;
use File::Path;
use POSIX qw/strftime/;

my @target_directories = qw(C:/ /full/path/to/test1  /full/path/to/test2);
my $files_moved = 'test.log';
my $signal;
my $signalled;

$| = 1; #flush buffers

my @all_signals = qw (STOP KILL ABRT QUIT TERM INT TSTP HUP);

sub signal_handler {
  $signal = shift;
  $signalled++;
}

foreach my $sig (@all_signals){
  $SIG{$sig} = \&signal_handler;
}

foreach my $xdir (@target_directories) {

  chdir $xdir or die $!;

  opendir my $dh, $xdir or die $!;

  while (defined (my $xfile = readdir $dh)) {

    next if ($xfile =~ m/^\./);  #skip dot files . and ..
    next if -d $xfile;

    my @calendar = localtime((stat $xfile)[9]);
    my $dir = strftime('%Y/%B/%d', @calendar);
    $dir =~ s/0(\d)$/$1/; # Change /01 etc. to /1

    mkpath $dir, 0, 0750;
    move $xfile, $dir or die $!;

    open my $files_moved_fh, '>>', $files_moved or die $!;
    print $files_moved_fh "$xfile => $dir\n";
    close $files_moved_fh;
  }

  last if $signalled;
}

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/


Reply via email to