ZSH Gem #1: Programmable file renaming

Posted by | Comments (8) | Trackbacks (0)

Welcome to the first article of this year's Advent calendar series. The last Advent calendar was extremely successful so I thought it would be a good idea to continue this.

The topic for the Advent calendar series 2011 is “24 Outstanding ZSH Gems” because the Z Shell is my absolute favorite shell. There's nothing ZSH can't do except the dishes. In my opinion it's much more powerful than any other shell out there. If you are not a ZSH user (yet?), you're still very welcome to enjoy this series as well. Maybe then you'll make the switch. And if not: some features also work similarly in Bash, although they might be not so comfortable there. wink

Now let's begin with programmable renaming of files or batch renaming. That sounds very abstract, but let me show you what I mean.

The normal procedure to move or rename files is to use mv:

mv source dest

This is done pretty quickly and you can use the normal globbing functions your shell provides (which BTW are very mighty in ZSH, but I will explain that in a later article). But what if you could use the expanded globbing parts of source in dest? That would make batch renaming of files a lot easier. Normally you would do this by looping over all files, checking if their names match a pattern and then renaming them. Alternatively, you could use find and do the renaming with the -exec parameter, but that is also a bit tricky. With zmv, however, you can do that with just one simple command.

Let's assume you want to rename all files ending with .txt to .html. We can do that:

autoload -U zmv
zmv '(*).txt' '$1.html'

The first line just loads the zmv module. You only need to do that once per session. Normally you would put that into your .zshrc file under your home directory. The second line is the main line. Here we perform the rename operation. You can see: we have put the globbing operator * into parentheses. That creates a back reference which we can then use in the second parameter as the variable $1. More back references would of course be available through $2, $3 etc. You might know this from other programming languages such as Perl, PHP or JavaScript when working with regular expressions.

This was one very simple command. But we can do more. I won't explain the more advanced globbing operators here (I'll do that in a later article), but one thing I can show you here is parameter substitution (or parameter expansion, as it's called in ZSH). That's something Bash knows as well, but in combination with zmv this becomes very handy. Parameter expansion is a feature to perform operations on shell parameters, i.e. on variables. So we can, e.g., do search and replace operations. If we want to replace all underlines in file names with dashes, we could either use:

zmv '(*)_(*)' '$1-$2'

or we could utilize parameter expansion:

zmv '(*_*)' '${1//_/-}'

The first one looks a bit ugly but less complicated, but the second one is much more flexible since we only need one back reference and can do any string operation on it. For instance, we can make all file names uppercase:

zmv '(*)' '${(U)1}'

or lowercase:

zmv '(*)' '${(L)1}'

or replace the file names with their lengths (usually not a good idea):

zmv -n '(*)' 'This file name was ${#1} characters long'

or whatever. Parameter expansion is a very complex topic, but I'll put a link for that below this article.

Be aware, that only globbing operators within parentheses are saved as back references. If you want to have back references of all globbing parts (i.e. implicit parentheses), use the zmv parameter -w.

One last thing to mention: you should always do a dry run first. You can do that with the parameter -n. That will show which operations would be performed without actually executing any rename or move operation.

Read more about zmv:

Trackbacks

No Trackbacks for this entry.

Comments

There have been 8 comments submitted yet. Add one as well!
Zach
Zach wrote on : (permalink)
ZMV doesn't have to use regex replacement. The following works exactly how you'd expect it to. autoload zmv zmv '*.txt' '*.html'
Zach
Zach wrote on : (permalink)
In the previous comment, it looks like it auto-formatted. It should read: pre. autoload zmv zmv '*.txt' '*.html'
rixed
rixed wrote on : (permalink)
What's wrong with the rename command ?
Mike
Mike wrote on : (permalink)
rename is a perl thing and isn't installed as standard (not on OS X, for instance). Good tip, thanks - switch to zsh from tcsh a few years back and haven't looked back, but I'm aware I've barely scratched the surface... I'll be following this series closely.

Write a comment:

E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

By submitting a comment, you agree to our privacy policy.

Design and Code Copyright © 2010-2025 Janek Bevendorff Content on this site is published under the terms of the GNU Free Documentation License (GFDL). You may redistribute content only in compliance with these terms.