[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 252
  • Last Modified:

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
0
austerhaus
Asked:
austerhaus
1 Solution
 
TintinCommented:
Much better/easier with a shell script

#!/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
0
 
Adam314Commented:
>>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);
}
0
 
austerhausAuthor Commented:
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_image-001.jpg

when I started with this:
images_image-001.jpg
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
ozoCommented:
cd $HOME
perl -MFile::Find -e 'find({no_chdir=>1,wanted=>sub{/\.jpg$/and($newfile=$_)=~s#(?<\!^.)/#_#g&&(rename $_,$newfile or warn "$newfile $!")&&print "$newfile\n"}},".")' >> logfile.txt

0
 
TintinCommented:
If you want it to run from your current directory, simple do:

#!/bin/sh
LOG=logfile.txt
HERE=`pwd`

for file in `find $HERE -name "*.jpg"`
do
  newfile=`echo $file|sed -e "s#$HERE/##" -e 's#/#_#g'`
  mv $file `dirname $file`/$newfile && echo "`basename $file` $newfile" >>$LOG
done
0
 
austerhausAuthor Commented:
Great. Thank you for the assistance Tintin.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now