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:
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.
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 ]
[ Parent ]
[ Parent ]
[ Parent ]
[ Parent ]
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 ]
[ Parent ]
[ Parent ]
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 ]
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 ]
[ Parent ]
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 ]
[ Parent ]
[ Parent ]
[ Parent ]
[ Parent ]
[ Parent ]
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.
perl -e 'for (@ARGV) { ($new=$_) =~ tr/[A-Z]/[a-z]/; rename $_, $new unless -e $new }' *.html
[ Parent ]
[ Parent ]
[ Parent ]
[ Parent ]
'vidir' should be mentioned. It allows editing directory contents in a (powerful) text editor.
Use "aptitude install moreutils" to get the utility.
--
...Bye..Dmitry.
[ Parent ]
[ Parent ]
[ Parent ]
[ Parent ]
for i in VTS_??_1.VOB; do j=${i/_1.VOB}; j=${j/VTS_}; mencoder $i -oac mp3lame -ovc lavc -o $i.avi; done
[ Parent ]
[ Parent ]
[ Parent ]
[ View Weblogs ]
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 ]