Rename files using directory names

P

Peter Jamieson

I have inherited many .rtf files contained in a directory structure like:
patient_data/patient1/2007_07_11/test1.rtf
where there are many patient directories such as patient1, patient2 etc
and many date directories such as 2007_07_11, 2007_07_09 etc
and there may be many .rtf files per patient and date combination.

What I would like to do is create new unique names for each .rtf file
based on the directory names: eg patient1_2007_07_11.test1.rtf
and put them into a new directory named patient_files.

I have checked out File::Find and tested the following script.
It lists all the files OK as expected like test1.rtf, test2.rtf etc
It merely replaces "_" with " " just as a test script.

However I cannot figure out how to do a rename for what
I would like the new file names to be namely in the
form of: patient1_2007_07_11.test1.rtf

Any help appreciated!, Cheers Peter

#!/usr/bin/perl
use warnings;
use strict;
use File::Find;

my $dir = '/patient_data/patient';

find(\&underscores, $dir);

sub underscores {
next if -d $_;
next if /^\./;
next unless /_/;
my $new_name = $_;
$new_name =~ s/_/ /g; # just for testing!
chdir($File::Find::dir);
rename($_, $new_name) or die $!;
print "$new_name \n";
}
 
J

John W. Krahn

Peter said:
I have inherited many .rtf files contained in a directory structure like:
patient_data/patient1/2007_07_11/test1.rtf
where there are many patient directories such as patient1, patient2 etc
and many date directories such as 2007_07_11, 2007_07_09 etc
and there may be many .rtf files per patient and date combination.

What I would like to do is create new unique names for each .rtf file
based on the directory names: eg patient1_2007_07_11.test1.rtf
and put them into a new directory named patient_files.

I have checked out File::Find and tested the following script.
It lists all the files OK as expected like test1.rtf, test2.rtf etc
It merely replaces "_" with " " just as a test script.

However I cannot figure out how to do a rename for what
I would like the new file names to be namely in the
form of: patient1_2007_07_11.test1.rtf

Any help appreciated!, Cheers Peter

#!/usr/bin/perl
use warnings;
use strict;
use File::Find;

my $dir = '/patient_data/patient';

find(\&underscores, $dir);

sub underscores {
next if -d $_;
next if /^\./;
next unless /_/;

You shouldn't use next from within a subroutine you should use return
instead. According to your example above your file names do not contain
a '_' character?

my $new_name = $_;
$new_name =~ s/_/ /g; # just for testing!
chdir($File::Find::dir);

By default File::Find::find() already has you in the $File::Find::dir
directory so this is superfluous. You should always verify that system
functions like chdir() have worked, but it doesn't matter if it failed
as you are already in the $File::Find::dir directory!

rename($_, $new_name) or die $!;

You are trying to move the current file to the same directory. You
probably want to include the new path name in the target:
"patient_files/$new_name" but you probably want to use an absolute path
instead of a relative path.

print "$new_name \n";
}


John
 
P

Peter Jamieson

John W. Krahn said:
You shouldn't use next from within a subroutine you should use return
instead. According to your example above your file names do not contain
a '_' character?



By default File::Find::find() already has you in the $File::Find::dir
directory so this is superfluous. You should always verify that system
functions like chdir() have worked, but it doesn't matter if it failed
as you are already in the $File::Find::dir directory!



You are trying to move the current file to the same directory. You
probably want to include the new path name in the target:
"patient_files/$new_name" but you probably want to use an absolute path
instead of a relative path.




John

Thanks John!....your comments have been most useful.
I will need to look at the use of "next" and "return" in
more detail....cheers, Peter
 
P

Peter Jamieson

Jim Gibson said:
Those should be 'return' statements, as you are not in an explicit loop.


There is no need to chdir here, as find will do it for you as long as
you have not set the nochdir option.


You need to 1) get the full path name, 2) strip off the leading
directory, 3) change all of the path separators to underscores, 4) add
the new directory name at the front. Something like:

#!/usr/local/bin/perl
use warnings;
use strict;
use File::Find;

my $dir = '/patient_data';
my $newdir = '/patient_files';

find(\&moveit, $dir);

sub moveit {
return if -d $_;
return if /^\./;
my $new_name = $File::Find::name;
$new_name =~ s{^$dir/}{};
$new_name =~ s{/}{_}g;
$new_name = "$newdir/$new_name";
rename($File::Find::name,$new_name);
}

You might want to check if $new_name already exists.

Hi Jim,
Thank you for your comments and suggestions!
I will rewrite some code based on the example you gave.
Your comment to check if a file name may already exist
is apt as by manual inspection I have noticed many
apparently duplicate files.
John Krahn has also mentioned my faulty use of "next" and "return"
so I need to correct my understanding of the difference.
Your help is greatly appreciated!...cheers, Peter.
 
J

John W. Krahn

Please don't quote sigs. TIA

Thanks John!....your comments have been most useful.
I will need to look at the use of "next" and "return" in
more detail....cheers, Peter

next (and last and redo) are loop (for, foreach, while, until and {})
control keywords.

perldoc perlsyn (specifically the "Loop Control" section.)


return is a keyword specifically for the purpose of returning from
subroutines.

perldoc perlsub




John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,816
Latest member
SapanaCarpetStudio

Latest Threads

Top