austerhaus
asked on
Script to rename a file based on its directory structure
Hello,
I have hundreds of image files in multiple directories that I would like to rename. Essentially, I want to prepend the directory structure to the filename and leave the file in its original directory. I would also like it to log the changes that it makes to a single logfile. Please let me know if there is anything that I need to clarify.
As an example:
/dir1
|-dir2
|-image-001.jpg
|-image-002.jpg
would become:
dir1_dir2_image-001.jpg
dir1_dir2_image-002.jpg
and the logfile would show:
image-001.jpg dir1_dir2_image-001.jpg
image-002.jpg dir1_dir2_image-002.jpg
I have hundreds of image files in multiple directories that I would like to rename. Essentially, I want to prepend the directory structure to the filename and leave the file in its original directory. I would also like it to log the changes that it makes to a single logfile. Please let me know if there is anything that I need to clarify.
As an example:
/dir1
|-dir2
|-image-001.jpg
|-image-002.jpg
would become:
dir1_dir2_image-001.jpg
dir1_dir2_image-002.jpg
and the logfile would show:
image-001.jpg dir1_dir2_image-001.jpg
image-002.jpg dir1_dir2_image-002.jpg
>>Much better/easier with a shell script
as long as you are on unix :)
Basically the same code in perl:
#!/usr/bin/perl
use File::Find;
$LOG=/path/to/logfile
find(\&ProcessFile, "/dir1");
sub ProcessFile {
return if $File::Find::name !~ /\.jpg/i; #skip any non-jpg files
return if !-f $File::Find::name; #skip any non-files (eg: directories)
$newfile=$File::Find::name ;
$newfile =~ s#/#_#g;
rename $File::Find::name, $File::Find::dir . "/" . $newfile
open(LG, ">>$LOG") or die "Couln't open log: $!\n";
print LG $File::Find::name . ", " . $File::Find::dir . "/" . $newfile . "\n";
close(LG);
}
as long as you are on unix :)
Basically the same code in perl:
#!/usr/bin/perl
use File::Find;
$LOG=/path/to/logfile
find(\&ProcessFile, "/dir1");
sub ProcessFile {
return if $File::Find::name !~ /\.jpg/i; #skip any non-jpg files
return if !-f $File::Find::name; #skip any non-files (eg: directories)
$newfile=$File::Find::name
$newfile =~ s#/#_#g;
rename $File::Find::name, $File::Find::dir . "/" . $newfile
open(LG, ">>$LOG") or die "Couln't open log: $!\n";
print LG $File::Find::name . ", " . $File::Find::dir . "/" . $newfile . "\n";
close(LG);
}
ASKER
Thasnks for the reply. Is there a way to modify this so that I am not required to manually specify the directory path? Basically, I would prefer if it simply prepended the directory structure from where the script is run down to the location of the file. I know my initial post sorta mucked up the the intention. I hope this is clearer:
A better example:
/root
|home
|dir1
|-dir2
|-image-001.jpg
|-image-002.jpg
would become:
dir1_dir2_image-001.jpg
dir1_dir2_image-002.jpg
...when I run the script from the home directory.
To get it to work, I had to change:
#!/bin/sh
LOG=logfile.txt
for file in `find /home/user/temp/test -name "*.jpg"`
do
newfile=`echo $file|sed 's#/#_#g'`
mv $file `dirname $file`/$newfile && echo "`basename $file` $newfile" >>$LOG
done
This gives me the following results:
_home_user_temp_test_dir2_ images_ima ge-001.jpg
when I started with this:
images_image-001.jpg
A better example:
/root
|home
|dir1
|-dir2
|-image-001.jpg
|-image-002.jpg
would become:
dir1_dir2_image-001.jpg
dir1_dir2_image-002.jpg
...when I run the script from the home directory.
To get it to work, I had to change:
#!/bin/sh
LOG=logfile.txt
for file in `find /home/user/temp/test -name "*.jpg"`
do
newfile=`echo $file|sed 's#/#_#g'`
mv $file `dirname $file`/$newfile && echo "`basename $file` $newfile" >>$LOG
done
This gives me the following results:
_home_user_temp_test_dir2_
when I started with this:
images_image-001.jpg
cd $HOME
perl -MFile::Find -e 'find({no_chdir=>1,wanted= >sub{/\.jp g$/and($ne wfile=$_)= ~s#(?<\!^. )/#_#g&&(r ename $_,$newfile or warn "$newfile $!")&&print "$newfile\n"}},".")' >> logfile.txt
perl -MFile::Find -e 'find({no_chdir=>1,wanted=
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Great. Thank you for the assistance Tintin.
#!/bin/sh
LOG=/path/to/logfile
for file in `find /dir1 -name "*.jpg"`
do
newfile=`echo $file|sed 's#/#_#g'`
mv $file `dirname $file`/$newfile && echo "`basename $file` $newfile" >>$LOG
done