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

Hello Monks,

I am in need of some advice. I've been coding for a few weeks now and I'm stuck on a part of my project. My goal is to have my code search through the directory for particular log files and to have them copied to a new location.

the problem comes from the fact that these files (which reside in different folders) have the same name. When I have them copied to the new location it overwrites the previous files (Which the contents are not the same).

I was trying to implement a renaming scheme that allowed for these files to be renamed when found and then copied over, but when I execute the code it only copies the original name to the new location (Over writing the previous ones). No error codes to share and I've consulted CPAN and perldoc. Any suggestions would be greatly appreciated.

Here is a copy of my code:
use warnings; use strict; use File::Find; use File::Copy; my $DirDestination = 'C:\Users\rfencer\Desktop\Log Files'; my $count= 0; find( { wanted => \&findfiles, }, "\\\\lefatols\\Kye230700-E\\DAT98\\KT11442\\Usr\\Results500\\R54_Nx\\5 +BLC" ); sub findfiles{ @ARGV = glob('*.log'); if (@ARGV){ my @copy= @ARGV; foreach $_(@copy){ if($_=~/run/i){ ReName($_); # rename($_,$count); copy($_, $DirDestination) or die($!); $count+=1;}}} }; sub ReName{ my $oldfn= 'Run.log'; my $newfn= $oldfn."$count"; my $send= rename($oldfn, $newfn); } print $count;

Replies are listed 'Best First'.
Re: File::Copy renaming trouble
by hippo (Archbishop) on Jun 14, 2016 at 22:20 UTC

    This is, AIUI, precisely the functionality provided by File::Copy::NoClobber. Unless this is a learning exercise I don't see any advantage to reinventing that particular wheel. HTH.

      LOL ++. I reinvented the wheel, just for something to do. :) Doesn't work correctly though, so I'm bailing and going with the module route.

Re: File::Copy renaming trouble
by stevieb (Canon) on Jun 14, 2016 at 22:59 UTC

    Welcome to the Monastery, NoobCoder!

    Use hippo's advice. This code doesn't do what I quickly put it together to do...

    I've rearranged a few things and made some subtle changes. I've also used File::Find::Rule as it's more flexible (allows you to specify wildcards, and doesn't require a callback). I also use File::Basename, as basename digs out only the file name and throws away the path part. There are most definitely better ways to do this than this code I've put together quickly, but it'll give you some ideas.

    I started with a directory structure like this:

    Original 'from' dir:

    test/ run1.log run2.log run3.log

    ...and the copy-to dir:

    test2/ run2.log run2.log_1 run2.log_2

    Now, in the code, what I've done, is create a recursive subroutine that checks if the original file is already in the destination directory, and if it is, it appends a _N to the end, where N is an integer. It iterates continuously, and will use the first available filename.log_N that is available:

    use warnings; use strict; use File::Basename; use File::Copy; use File::Find::Rule; my $count = 1; my $dir = 'test'; my $to_dir = 'test2'; my @files = File::Find::Rule->file() ->name('*.log') ->in($dir); if (@files){ for (@files){ if ($_ =~ /run/i){ my_copy($_); } } } sub my_copy { my ($base_file, $file_name) = @_; # get just the filename my $file = basename $base_file; # $file_name will be empty on the initial call... # let's set it so it's not undef $file_name = $file if ! $file_name; if (-e "$to_dir/$file_name"){ # strip off the _N suffix if present $file_name =~ s/_\d+$//; # append a new _N, then increment the count $file_name = "${file}_$count"; $count++; my_copy($base_file, $file_name); } else { print "copying $base_file to $to_dir/$file_name\n"; copy $base_file, "$to_dir/$file_name" or die $!; } }

    With the example directories above, the result is this:

    test2/ run1.log run2.log run2.log_1 run2.log_2 run2.log_3 run3.log

    On second pass:

    test2/ run1.log run1.log_1 run2.log run2.log_1 run2.log_2 run2.log_3 run2 +.log_4 run3.log run3.log_1