One of the most common tasks for those new to Linux is batch file renaming. If you’re not used to a Linux shell, this can seem like a task that is bound to be manual and time-consuming. But there are many ways to speed up the process; you just need to know which is best.

Example File Move Tasks

To demonstrate each approach, I’ll use two examples that represent common renaming tasks you may want to carry out. There are many different ways you might want to rename files, depending on their current names and what you’re actually doing. The two example tasks I’ll use can help to illustrate typical usage of each tool. However, you’ll need to investigate the tool of your choice further to understand how best to use it for your particular needs.

Working out what you actually want to do is probably the hardest part of batch file renaming. Consider which parts of each file’s name you might want to delete, which you might want to keep, and which you might want to translate into something else.

The first task is to change the extension of all matching files in the current directory. For example, changing a “.txt” extension to “.md” should rename test-001.txt to test-001.md, and rename ANOTHER.txt to ANOTHER.md. It should apply to files ending with “.txt” and no others.

The second task is a bit more complicated, to show some more advanced features of these tools. It should remove a specific part of a filename, keeping everything else intact. It should apply to all files, recursively. Specifically, I’ll look for all files of the form DDDD_something.ext and rename them DDDD.ext. So it should change 1234_this-is-my-doc.doc to 1234.doc and docs/9999_about.txt to docs/9999.txt.

1With a for Loop, Globbing, and Parameter Substitution

This first approach uses several features of the bash shell, which many other shells have borrowed. First up is the humble for loop, which it will use to iterate over a set of candidate files. Secondly, it identifies those files using a glob, a type of pattern that’s optimized for filename matching. Finally, this approach use a syntax that lets you modify strings based on certain patterns, called parameter substitution.

For the first task, you can change .txt extensions into .md using this shell code:

The for loop iterates through all files that match the glob./*.txt. This will match all files in the current directory that end in the “.txt” extension.

The command inside the for loop moves the file to a new name, which it generates with the % operator. This symbol removes from a string the shortest part of a pattern that matches the end of it. In this case, it removes “.txt” from the end of each filename, then adds “.md” to the end.

All the examples in this article are illustrative and should not be used naively in a production environment. For a robust solution, you should consider whether your files can contain special characters—in particular, spaces—and you should always have a backup policy to guard against failures.

The second task starts off with a much more complicated glob pattern to handle both recursion and a wider set of files:

The./**/expands to match the current directory and any nested directories, at any level below this one. The[[:digit:]]pattern matches a single digit, so four in a row, followed by an underscore, will match our required files.

ensure you understand which shell you are using to run this command, and which globbing features it supports.

To enable recursive globbing in Bash 4+, make sure you runshopt -s globstar, either as a one-off command or within your script. On Mac, the zsh shell supports recursive globbing by default.

2With a for Loop and sed

Another option for the command inside your for loop issed, the stream editor. The sed program should be available on any Linux, including macOS.

The difference in this version is that the parameter substitution is replaced with command substitution and a call to sed. The$(…)syntax causes the command to run and its output to be substituted at this point.

The regular expression passed to sed replaces the “txt” value at the end of each filename with “md”. The $ in the pattern ensures the match takes place at the end of a filename.

In the second task, the regular expression gets even more complex, although the basic approach remains the same:

Note that sed’s regular expression syntax supports repetition operators like{4}, which lets you avoid the more verbose approach in the glob pattern.

Although these sed solutions are a little longer than their parameter substitution counterparts, they can be more readable, especially for those with an understanding of regular expressions and sed. Its support for regular expressions, along with various other features, means that sed is a far more powerful alternative. For complex requirements, this can make it a preferred option.

3Using the rename Command

The rename command is a Perl script with support for running arbitrary Perl code, optimized to handle file renaming. This means it’s very powerful, although you’ll need to install it on a system with Perl available.

Once installed, rename is very easy to use for simple tasks, such as the extension-renaming of our first example:

Note how the regular expression is identical to the one in the equivalent sed example. Here, though, the benefit is in rename’s handling of the filename inputs. The program will apply its substitution to each filename argument, so using a glob that expands to all .txt files means you can complete the task with a one-liner.

The rename command supports a-n/–dry-runoption, which prints a log of potential changes, without actually renaming files. This is an excellent safety net which I recommend you use wherever possible.

You also need just a one-line command for the second task, even if the regular expression is a little more complicated.

Note, again, that this takes advantage of the extended blog support for recursive directories.

4Use zmv With zsh

If you usezsh, the Z shell, there’s another option at your fingertips, provided you enable it first. zmv is a shell function that acts like a simplified version of rename. You’ll need to load it—either on a case-by-case basis, or via a startup script like .zshrc—using this command:

Once enabled, you may call zmv like so, to carry out the first task:

Unlike rename, zmv takes us back to globbing instead of regular expressions, so it’s a bit less powerful. But, as you can see from this example, it’s easy to use; the -W option simplifies the syntax even further beyond the default.

Since it’s a shell function, zmv doesn’t have a built-in man page. But you’re able to find out some info about it viaman zshcontribinstead. In particular, note that it also supports a-noption to carry out a dry run.

Since zms requires zsh, it benefits from the extended globbing that the shell provides, including recursing into subdirectories.

Without regular expression support, this pattern is a little longer, but still very readable.

5Using mmv

mmv stands for “multiple move” and it’s another tool specifically designed to handle bulk file renaming. You’ll probably need to install it, but this is just a simple case ofsudo apt install mmv(Ubuntu),sudo yum install mmv(RHEL/CentOS/Fedora),brew install mmv(Mac), or the equivalent in your package manager of choice.

Once installed, you may use the tool to rename extensions easily:

The big difference with mmv is how it handles patterns and matches. In addition to the most familiar wildcards, mmv also supports a;wildcard which you can use to match any number of directories, which supports the recursive nature of the second task:

Note also how mmv supports references to matches, not via the typical parentheses, but by assigning a unique number to each individual wildcard. This gives us seven different matches in the final replacement expression: one for the leading path matched by;, one for each of the four digits, one—#6—for any characters after the underscore, which we discard, and one for the extension following the period.

Because of this approach, mmv might be too cumbersome for tasks that involve too many wildcards in the initial pattern. But when carrying out tasks like the common extension swap, it’s hard to beat for simplicity and readability.

While there are many options for bulk file renaming in Linux, each one takes a bit of getting used to. I recommend picking one that looks the most approachable, and getting to know it as well as you’re able to, making liberal use of the-n/–dry-runoption for those tools that support it.

If you’re a fan of regular expressions, it’s hard to beat their sheer power, and a tool like rename will probably serve you well. If, on the other hand, you’re more of a shell guru, a wizard with wildcards, you’ll probably like the look of zmv or mmv. But those tools are only good if you use the Z shell, or if you install them and learn their idiosyncratic syntax, respectively.

Meanwhile, parameter substitution can be surprisingly powerful, and you may well want to repeat your bulk file renaming, so writing a shell script has further benefits. Ultimately, the choice is yours, and any of these options is preferable to manually renaming hundreds of files using a GUI. That’s the power of the command line.