Easily renaming multiple files.
Posted by Steve on Wed 1 Jun 2005 at 05:29
Renaming multiple files seems to be a problem which many newcomers to shell scripting, or administration, have problems with. But once you've done it a few times the actual solutions are very simple.
There are many cases where you might have a large number of files to rename en masse, for example files which are output from a given script or tool. Or files that must be renamed to be uploaded to a web-host.
How you rename the files mostly depends on which tools you have available, and which shell you're using.
The way I tend to rename large numbers of files is the same way that I tend do any job which requires running the same command on a number of files - I use the looping facility within the bash shell.
For example lets assume you have several files in a directory a.JPG, b.JPG, c.JPG and d.JPG then you can work with each one as follows:
skx@lappy:~$ for i in *.JPG; do echo $i; done a.JPG b.JPG c.JPG d.JPG
This command has worked with each file which matches the pattern "*.JPG", and runs a command on each file - in this case it's "echo $i".
Obviously the command which we're running, here it is echo, can be replaced with other commands.
If we used to use this style of command to rename each of the files to lowercase their extensions we have two possible approaches:
- Take advantage of bash's variable substituion.
- Use the standard unix command basename.
The bash shell has a notion of text substitutions which is very powerful, and something that can be very useful to know about so we'll cover that first.
The simplest example I can think of is to strip the extension. For a filename which is stored in the shell variable $i you can strip a known extension with this:
skx@lappy:~$ i=a.JPG
skx@lappy:~$ echo $i
a.JPG
skx@lappy:~$ echo ${i/.JPG/}
a
Here we've used the substitution operation to strip the ".JPG" from the end of our variable - we can plug this into the loop we showed earlier to force a rename:
skx@lappy:~$ ls
a.JPG b.JPG c.JPG d.JPG
skx@lappy:~$ for i in *.JPG; do mv "$i" "${i/.JPG}".jpg; done
skx@lappy:~$ ls
a.jpg b.jpg c.jpg d.jpg
(The "quotes" around the arguments to the mv command are useful if you're ever working with files which contain strange characters, or spaces, in their names).
This is the basic way that you can rename files with bash - use a loop to work on each file, then use the built-in substituion operations to strip or add to each name in turn.
The other approach is to use basename to manipulate filenames. basename is a standard command which allows you to strip suffixes from filenames:
skx@lappy:~$ basename c.jpg .jpg c skx@lappy:~$ basename c.jpg pg c.j
Here you can see that the command just returns the filename you've specified with the second argument removed from it.
This can be plugged into our loop like this:
skx@lappy:~$ ls a.jpg b.jpg c.jpg d.jpg skx@lappy:~$ for i in *.jpg; do mv "$i" "`basename $i .jpg`.JPG"; done skx@lappy:~$ ls a.JPG b.JPG c.JPG d.JPGUsing Specialised Commands
Instead of remembering how to run these loops over files with bash, you can instead rename files en masse with specialised renaming commands.
A simple one is the rename command which is included with the Debian perl package and almost certainly available to you already.
The rename command allows you to rename files with full perl expressions, in a simple manner.
For example our preceeding example of changing the extension can be achieved with:
skx@lappy:~$ rename 's/\.JPG/\.jpg/' *.JPGWe can also, for example, strip spaces from filenames with this:
skx@lappy:~$ rename 's/ //' *.JPGRenaming files from upper to lower case can be a simple job:
skx@lappy:~$ rename 'y/A-Z/a-z/' *There are also other specialised commands which you can locate with the apt-cache command, such as mmv and mrename.
I was usually renaming files one by one, because I was too lazy to write bash scripts or one-liners to do that.
I knew there were commands to do that but I never really searched. Your article made me discover the "rename" command, which seems simple but also pretty powerfull thanks to the use of perl regexp. I have been using Debian for 4 years, but never used it before !
--
Arnaud
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Thanks - I'm glad you liked it.
I'm often unsure of the right level to pitch things at, so I figure some "simple" pieces and some "complex" pieces will please most people.
Steve
-- Steve.org.uk
[ Parent | Reply to this comment ]
for i in *.jpg
is equivalent to
for i in a.jpg b b.jpg
so "echo $i" will be executed 3 times and for files which actually don't exist ("b" and "b.jpg")
Does anyone have a solution to this?
[ Parent | Reply to this comment ]
i.e.:
for i in `ls *.jpg` will have the problem you describe, as will
for i in `find -name *.jpg`
When I ran into that problem, I ended up just using 'for i in *.jpg' without using a backticked command to work around it.
[ Parent | Reply to this comment ]
for file in $(ls *.ps); do newfile=$(echo $file | sed -e s/\.ps/\.jpg/); convert $file $newfile; done
of course for renaming you just change convert to mv....
just my $.02
[ Parent | Reply to this comment ]
for file in *.ps
do
convert $file ${file%%.ps}.jpg
done
#;-)
[ Parent | Reply to this comment ]
for i in `cat file`; do blah blah "$i"; done
So I use the following instead:
cat file | while read i; do blah blah "$i"; done
And that works as "read" reads in a line at a time.
Now I tend to use this method for everything and hardly ever use "for".
[ Parent | Reply to this comment ]
I think cat is the problem on this.
For me, a better syntax for processing a file line by line is:
while read LINE do blah blah blah done < $1
Just specify the file on the command line, or you can replace the $1 with the filename or full path to the file.
[ Parent | Reply to this comment ]
It's best used in a script like this:
IFS=$'\t\n'
This changes IFS to only trigger on tabs and newlines.
The default is to trigger on spaces as well, like this:
IFS=$' \t\n'
Just beware of commands that rely on IFS being in default state, if you notice any oddities.
[ Parent | Reply to this comment ]
I've got several files with names like u90021_dw_v001.txt, u90021_dw_v011.hdr etc in a UNIX directory. I would like to rename them to u90021_dw_v1.txt and u90021_dw_v11.hdr respectively and copy them within a folder as a backup. So basically I would like to remove 'one/two zeros' immideately after 'v'. Your help will be highly appreciated!
[ Parent | Reply to this comment ]
This is the other thing I end up needing to do a lot, so I thought I'd throw it in.
Say I use a local domain of prentiss.house because I live on Prentiss street, but then I move to Massachusetts Avenue and want to change my domain accordingly in my local DNS.
perl -pi -e's/prentiss.house/massave.house/g' /etc/bind9/*
Awesome.
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
I was saving that for my next piece!
(Although I usually use perl -pi.back -e "...." - to create a backup of the input file too).
Steve
-- Steve.org.uk
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
--Jim
[ Parent | Reply to this comment ]
--Jim
[ Parent | Reply to this comment ]
When you have thousands of files to rename, remove or do anything with, the "for" approach is very slow. And if you try to run the shell command (i. e. rm *.JPG) will not able to deal with so much files.
I found a more convenient way (and faster, too) is to use ls ands xargs, as describes this article in Unix Review
[ Parent | Reply to this comment ]
--Jim
[ Parent | Reply to this comment ]
'qmv *' will open an editor with all files in two columns. You edit the second column to your liking and the files will then be renamed.
[ Parent | Reply to this comment ]
mmv -r '*JPG' '#1jpg'
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
You can download it at: http://renamer.bounga.org
[ Parent | Reply to this comment ]
I want to copy them to windows box using ssh.
But, the file names are 'modified-Base64' which means that they contain characters that are not acceptable on windows.
Using ls in a script did not help. There are too many files in folders.
Plus, all I want to do is to traverse the folders and simply substitute a different char for the offending chars (if the file name contains them).
Can someone help me out, please
[ Parent | Reply to this comment ]
[ Send Message | View muondude's Scratchpad | View Weblogs ]
I often use Perl for these sort of tasks. Here are a couple of examples you can modify to solve your problem (substitute or remove the offending characters).
Command Line file renaming: rename a group of files with extension .html to .shtml extensions:
perl -e 'for (@ARGV) { ($new=$_) =~ s/(.+)(.)\.html$/$1$2.shtml/; rename $_, $new unless -e $new }' *.html
In your case you could use a regular expression for the offending characters and substitute them with whatever you like.
Convert a bunch of file names from UPPER case to lower case
perl -e 'for (@ARGV) { ($new=$_) =~ tr/[A-Z]/[a-z]/; rename $_, $new unless -e $new }' *.html
I strongly suggest you make a copy of some of your files first and test this out before letting it go on all your files.
You could also modify these perl scripts to be part of a shell script that loops over your 10^6 files, or write a full perl script to do that.
-- Sam
[ Parent | Reply to this comment ]
FYI on this topic: http://www.michael-forman.com/perl/ren-regexp.html
Fabio
http://www.rigadicomando.org
(what you see is what you Grep ;)
[ Parent | Reply to this comment ]
open folder which contain images or any other files.select images(files) which you want to rename sequentially.
now whatever files you are selected are appear in blue coloured selected files.
just right click on the first image(file) and select<a href="http://dadecoders.blogspot.com/2007/11/how-to-rename-100-files-at -time.html">; rename</a>here type "marriage"then press enterNow you can see that all the files are name as
marriage
marriage (1)
marriage (2)....
,
[ Parent | Reply to this comment ]
14280_aljuc_1.jpg
14280_aljuc_3.jpg
14280_LBL.jpg
14280_SUP.jpg
100_Fkidbld_3.jpg
110_Fkidbld_1.jpg
1001_Soothing_1.jpg
10100_Half_1.jpg
...
if there is a middle part in the name of the files I want to rename them and delete the middle text.which means I need to have these results:
14280_1.jpg
14280_3.jpg
14280_LBL.jpg
14280_SUP.jpg
100_3.jpg
110_1.jpg
1001_1.jpg
10100_1.jpg
plz help.thanks
[ Parent | Reply to this comment ]