Logo Computer scientist,
engineer, and educator
• Articles • Articles about computing • Utility corner

Cygwin logo

rename2 — a flexible command-line utility for batch renaming of files

What is this?

rename2 is a very flexible command-line renaming utility for files and directories. It is designed to tackle renaming problems that are not handled well by other utilties, such as as removing superfluous parts of a filename, or changing the case of filename extensions without altering the rest of the name. Because rename2 embeds the Lua scripting engine, it can perform name transformations of great complexity if required, although some experimentation maight be required to get the pattern matching rules right. Because of this need for experimentation, and the fact that mistakes could be catastrophic, rename2 won't actually make any changes to the filesystem unless it is invoked with the -x switch — something that should only be done when its results have been carefully checked.

rename2 was intended for use with Cygwin, but it builds cleanly on most Linux systems.

Overview and examples

rename2 is invoked like this:
$ rename2 [options] {pattern} {replace} {files...}
pattern is a Lua pattern, rather like a regular expression (but not exactly like a regular expression, so some care is required). replace is the text with which to replace the pattern in each filename, and may be either a simple string of text, or a Lua language function that evaulates to a string of text. The default is to treat the replacement as a simple string. files is a list of files to examine. If the --recursive switch is given, directories are expanded recursively. Needless to say, particular care has to be taken with this mode of operation.

By default, rename2 carries out no actions, but simply reports how many files would be renamed. Using the --debug switch reports more information about which specific files will be changed. Only if the --execute switch is given will any actual changes be made. I strongly recommend using --debug and checking the output very carefully before using --execute. It is very easy to make mistakes with the pattern syntax and change files that should not be changed.

Here is a simple example, which replaces all spaces in all filenames in the current directory with underscores (note that neither --debug not --execute is shown in these examples but, of course, one or other should be):

$ rename2 " " _ * 
Note that the space has to be quoted, else it will be removed by the shell.

In this example, both the pattern and the replacement text are simple strings. The default is to replace all occurences of the pattern, so this example replaces all spaces with underscores.

Here is a slightly more complicated example, which changes the names of all files ending in .JPG so they end in .jpg.

$ rename2 %.JPG$ .jpg * 
You might, just possibly, get away with saying
$ rename2 .JPG .jpg * 
But there are two problems. First, the dot (.) character is a wildcard in a Lua pattern (as in a regular expression). .JPG will match any character followed by JPG. Second, the pattern will match anywhere in the filename, not just the end. To match a literal '.', we need %.. The ensure that only the end of the filename is matched, we add $ to the end of the pattern. You can specify to match just the beginning of the filename by starting the pattern with '^', but that is probably a less common case.

This example separates all strings of digits frmo their preceeding text by an underscore character; for example, it changes track01.wav into track_01.wav:

$ rename2 %d+ _%1 *
This example might affect filenames you don't expect as well, so it might be necessary to experiment and adjust the patter as appropriate. The pattern %d match a digit, and %d+ matches one or more digits. In the replacement, the sequence %1 means 'replace with the first matched pattern component'. Since the pattern consists only of one component, %1 refers to the whole matched text.

A pattern can consist of multiple components, and if they match they can be referred to individually in the replacement text. This example replaces dots (.) with underscores:

$ rename2 "(.*)%.(.*)" "%1_%2" *
The parentheses group the text of the filename into two components on either side of the '.', then the replacement writes the two components separated by an underscore. Both the pattern and the replacement are quoted, to avoid interference from the shell (note that parentheses have a specific meaning to the shell if they are not quoted; the same is true, of course, of spaces).

Here is an example, showing the use of a Lua function call — string.upper() in this case. The --evaluate switch indicates that that the replacement text is a Lua function.

$ rename2 --evaluate ".*" string.upper *
This example renames all files to upper case. The pattern .* matches the whole filename. The result is passed to the Lua function string.upper(), which returns the upper-case equivalent of the original filename.

Finally, here is a much more complicated example.

$ rename2.exe --evaluate "(.*)(%..*)$" "function(a,b) return a .. string.upper(b) end" *
This replaces all file extensions with their upper-case equivalents, leaving the rest of the filename as it is.

The pattern consists of two parts, grouped by the parentheses. (.*) matches any number of any character. (%..*)$ matches a literal '.', followed by any number of any character, but only at the end of the filename. The $ is outside the parentheses, because we want to capture the text of the file extension, not the end-of-line indicator. When the pattern matches, replace2 calls a Lua function with one argument for each component in parentheses. In this case, the function is called with two arguments — one for the part of the name before the extension, and one for the extension. The arguments can have any names, so long as they match in the function text the names used in the function definition. Here the function returns a string formed by concatenating (.. is the concectenate operator in Lua) the value of the first match to the upper-case version of the second.

Anything more than very simple use of rename2 will require some knowledge of Lua patterns. These are described here. General information on the Lua scripting language is here.


It is important to understand that, when using the --evaluate mode of operation, the replacement argument is not an arbitrary Lua expression, but a function to evaluate. You can't use, for example, an expression like this:
  string.upper .. ".new"
The reason is that you can't define a function in a Lua expression, but you can refer to arbirary expressions in a function that you define. To have replace2 evaluate a Lua expression, rather than a function, would mean that only built-in functions could be used. In reality, this might not be much of a limitation, but it seemed appropriate to gain a large amount of additional flexibility at the expense of a small increase in complexity.

Some of the examples in this note refer to changing the letter case of a filename. You should be aware that, on the Windows platform, even under Cygwin, this is problematic. rename2 won't overwrite an existing file during its operation, and if two files differ only by their filename, Windows assumes that they are the same file. This is a very awkward problem to get around, and one for which the blame has to lie with Microsoft.

Legal, etc

rename2 is copyright (c)2012 Kevin Boone, distributed according to the GNU Public Licence, version 2. In essence that means that you may do whatever you like with the software, at your own risk, provided that the original authorship remains clear. There is no warranty of any kind. Please be aware that careless use of this utility can turn your filesystem into gibberish.


Source code
Cygwin binary
Copyright © 1994-2013 Kevin Boone. Updated Feb 07 2013