There’s been a fair amount of discussion recently regarding filename renaming, and while this is indeed one of those things that there are as many ways to do as there are to skin a cat, here’s an example of one way, with a bit of explanation as to how you can customize to suit your own needs.So, here was my exact situation, I had multiple folders with 1000s of files named in a similar, but not identical manner that I needed to rename. The Files in question looked like this “1166139013.000207.mbox:2,” where the first string of numbers was always the same number of characters, but were varied numbers, the second set of numbers were unique, but signified the numerical designation of the file, and the rest of it I really didn’t need. In the long run I wanted “1166139013.000207.mbox:2,” to look like “207.”.
As I needed this to run recursively from a root that I designated, I knew I was going to have to use “find”, and indeed finding the files themselves was the easy part, indeed even stripping the filename down to where I needed it too was relatively simple in the grand scheme of things, actually having the renaming action performed, that was the tough part. I was used to using find, and slinging a “-exec” on the end to accomplish tasks in the past – like finding files older than a certain date and removing them:
<code> find /Volumes/backups/ -ctime +30 -maxdepth 1 -exec rm -rf {} ; </code>
One small problem with this when I was using “sed” to massage my filenames and the -exec, or course starting with -e was being interpreted by sed! Time to think again, and that’s where this one-liner came from:
<code> find /Volumes/Mail/imap/user * | awk '{print("mv "$1" "$1)}' | sed -e 's/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].0*//2' | sed -e 's/mbox:2.//2' | /bin/sh &> /dev/null </code>
So, the find is pretty vanilla, awk may be new to some though – officially it’s defined as a “pattern-directed scanning and processing language”… and in English what it gives you is the ability to take the output of any other comand and filter that to your own devices. To show exactly what awk is capable of doing, I could take the output of a “ps” command and only print the PID and actual process being run by me:
<code> ps -auxww | grep drina | awk '{print $2 , $11}' </code>
Where $2 is the PID and $11 is the process. There are endless possibilities here for use in process and resource monitoring.
The next portion of my one-liner is a sed command. sed is described as a stream editor in the man page, but for most it’s usage is as a “find and replace” tool. Once you start using sed however, you’re going to want all find and replace to function in the same manner, with the ability it has to accept regular expressions. At first glance this looks like a bit of a mess, but the regular expression is pretty straightforward in that the “[0-9]” indicates that the character in question could be any numberical character in the 0-9 range. For a full explanation of regular expressions, and how to use them to your power, check out the wikipedia entry on regular expressions.
Finally, while testing this, I’d left the /bin/sh off the end of this one-liner. This enabled me to ensure all the files I wanted to change were in fact going to format correctly. Passing everything previous to /bin/sh is based around the awk command we spoke about earlier, so it’s really sending a mv command to /bin/sh.
Of course there are many other ways this problem could have been approached, which is part of the beauty of any shell scripting – there’s so many right answers. Hopefully this will help with some of the more recent requests for filename renaming, while also helping you to discover a great pair of shell commands in sed and awk.
…..
Here’s a script I wrote a couple of weeks ago to find and rename files that
look like DOS short file names. These seem to occur when files with
names longer than 31 characters on a Windows server get copied to a
local drive on a Mac using Services for Macintosh.
It’s certainly no one-liner, but I like options. I meant to extend it to support
launch arguments for the find pattern and the sed command, but haven’t
gotten around to it. I gave up on one-line because I couldn’t figure out how
to make the find command support regular expressions. I didn’t think to
use it just to find everything. One-liners are hard to read, anyway.