Bulk & Automation

Bulk Rename Files on Linux: The One Reference That Compares Every Tool

Search for how to bulk rename files on Linux and you get five different answers, each assuming a different tool. One page shows the rename command with a Perl regex, the next shows a rename that takes plain positional arguments, a third insists you use mmv, a fourth swears by zmv, and a fifth just writes a for loop. They cannot all be describing the same command, and they are not. This page pulls those fragmented answers into a single reference. It explains what each tool actually does, gives you a decision rule for picking one, and shows you how to preview a batch rename before it touches a single file. By the end you will know which tool your distribution ships, which one fits the job in front of you, and how to run it without breaking anything.

Why Linux Renaming Feels Confusing (and How to Cut Through It)

The confusion comes from one word meaning two different programs. There are two entirely separate commands both named rename, and which one you have depends on your distribution. There is the Perl rename (often shipped as prename or rename on Debian and Ubuntu derivatives) that takes a Perl regular expression, and there is the util-linux rename (common on Fedora, CentOS, and many minimal installs) that takes three plain arguments and does a simple text substitution. They share a name and nothing else. On top of that pair sit two more capable tools, mmv for wildcard pattern renames and zmv for anyone working in the zsh shell, plus the universal fallback that always works: a for loop calling mv.

So the honest answer to how do I bulk rename files on Linux is a question back at you. Which rename do you have, and how complex is the mapping from old names to new ones? Answer those two things and the right tool falls out almost automatically. The rest of this reference walks each tool in the order you are most likely to reach for it, then gives you a table and a decision rule to lock the choice in.

The Perl rename: Regex Renames in One Line

The Perl version of rename is the most powerful of the built-in options because it accepts a full Perl substitution expression. The pattern is rename followed by a substitution and a file list. To replace every space in the current directory with an underscore you run rename 's/ /_/g' * where the s/ /_/g is a global substitution, space to underscore, applied to each matching filename. Because it is real regex you can do far more than swapping characters: rename 's/\.JPEG$/.jpg/' * lowercases and shortens the extension, and rename 'y/A-Z/a-z/' * transliterates every filename to lowercase in one pass.

The feature that makes it safe is the dry run. Add the -n flag and rename prints what it would do without renaming anything, so rename -n 's/ /_/g' * shows you a preview of every rename before you commit. Run that first, read the output, then run the same command without -n. Take a folder of camera exports where one file is IMG 2938.JPEG. Running rename -n 's/ /_/g; s/\.JPEG$/.jpg/' * would report IMG 2938.JPEG renamed as img... only after you also lowercase, so the full pipeline IMG 2938.JPEG turns into img_2938.jpg once your substitutions handle the space, the case, and the extension together. That is the Perl rename in a sentence: reach for it whenever the change is a regex.

The util-linux rename: The Simple Positional Swap

The other rename is far simpler and, on distributions that ship it, far more common. The util-linux rename takes three positional arguments: the text to find, the text to replace it with, and the files to act on. To turn every .jpeg into .jpg you run rename .jpeg .jpg *.jpeg. There is no regex here, just a literal from-text and to-text, which is either a limitation or a relief depending on the job. For a plain extension swap or a straight word replacement it is quicker to type and harder to get wrong than an escaped regex.

The catch is knowing which rename you are actually holding, because the syntax that works on one will fail or misbehave on the other. The quickest test is to run rename --version and read the first line: if it mentions util-linux you have the positional version, and if it mentions Perl or shows something like /usr/bin/rename you are on the Perl one. Another giveaway is behavior, if rename 's/a/b/' filename does nothing useful and just complains, you almost certainly have the util-linux build and need positional arguments instead. Check once per machine and you never have to wonder again.

mmv: Wildcard Pattern Mapping

When the rename is less a find-and-replace and more a structural remap of names, mmv is the tool built for exactly that. It is not always installed, so you may need to add it with your package manager (apt install mmv or dnf install mmv), but once it is there it handles wildcard-to-wildcard mappings cleanly. The idea is that wildcards in the source pattern are captured and referenced by position in the destination. Running mmv '*.jpeg' '#1.jpg' renames every .jpeg to .jpg, where the #1 stands for whatever the first wildcard matched. A file named holiday.jpeg becomes holiday.jpg, and vacation_02.jpeg becomes vacation_02.jpg, all in one command.

The power shows when you have multiple wildcards to shuffle. A pattern like mmv 'report_*_*.txt' 'report_#2_#1.txt' swaps two captured segments, which is awkward to express with either rename and tedious with a loop. mmv also refuses to clobber existing files by default and can report collisions before it acts, which makes it a comfortable choice when the mapping is intricate enough that you want a tool watching your back. Reach for mmv when the job is a complex wildcard mapping rather than a simple substitution.

zmv: The zsh Built-In

If your shell is zsh, you already have one of the best batch renamers on the system and may not know it. zmv is a zsh function you load once per session with autoload -U zmv, after which it renames using zsh glob patterns with parenthesized groups you reference as $1, $2, and so on. To back up every text file you run zmv '(*).txt' '$1.bak', where (*) captures the base name and $1 replays it with a new extension, so notes.txt becomes notes.bak. It reads a lot like the mmv idea but uses native zsh globbing, which means you get zsh's full pattern vocabulary, including recursive **/ matching, for free.

zmv also has a dry-run habit worth building: run it with -n to preview, as in zmv -n '(*).txt' '$1.bak', and it lists each rename it would perform without doing them. Because it is part of the shell rather than a separate binary, zmv is the natural pick for anyone who lives in zsh and does not want to install anything. The only prerequisite is remembering the autoload line, which many people simply drop into their .zshrc so zmv is always ready.

The for Loop: The Fallback That Always Works

When nothing is installed, when you are on a stripped-down container or a recovery shell, or when the logic is fiddly enough that you want plain visible steps, the for loop is the fallback that never lets you down. It works in bash, in sh, and in zsh, and it needs nothing beyond mv. A loop like for f in *.jpeg; do mv "$f" "${f%.jpeg}.jpg"; done walks every .jpeg file and renames it, using the shell's own ${f%.jpeg} parameter expansion to strip the old extension before appending the new one.

The loop trades brevity for control. You can insert an echo in front of the mv to preview, as in for f in *.jpeg; do echo mv "$f" "${f%.jpeg}.jpg"; done, which prints the commands without running them, your manual dry run. You can add conditionals, log each move, or build the new name from several pieces of the old one. It is more typing than a one-line rename, but it is portable to the point of being universal, and it is the answer whenever the environment is too minimal for the specialized tools or the naming logic is too custom for a single pattern.

The Decision Rule: Which Linux Rename Tool to Use

Here is the rule that collapses all of the above into a single choice. If the change is a quick regex, a substitution, a case change, a pattern strip, reach for the Perl rename and preview it with rename -n. If you have no rename installed or the job is a simple literal swap like one extension for another, use the util-linux rename with its positional arguments, or drop to a for loop if even that is missing. If the mapping is a complex wildcard rearrangement with captured segments moving around, use mmv. And if you are working in zsh, use zmv, because it is already there and speaks the shell's own glob language. Two questions decide it: which rename you have, and how complex the old-to-new mapping is.

Linux Rename Tools Compared

The table below lines up the four named tools across the traits that actually drive the choice, so you can match the job in front of you to the tool that fits it.

ToolBest forRegex supportDry runWhere it ships
Perl renameRegex renames, case changes, substitutionsYes, full Perl regexYes, rename -nDebian, Ubuntu (often as rename or prename)
util-linux renameSimple literal from-text to-text swapsNo, positional text onlyLimited, no true preview flagFedora, CentOS, many minimal installs
mmvComplex wildcard-to-wildcard mappingsWildcards, not full regexReports collisions, use with careNot default, install via apt or dnf
zmvPattern renames inside the zsh shellzsh globs with capture groupsYes, zmv -nBuilt into zsh, autoload -U zmv

A Note on Scanned Documents and OCR

One limit is worth stating plainly, because it trips people up. Every tool on this page renames by filename only. rename, mmv, zmv, and a for loop all operate on the string of characters that is the file's name; none of them can open a file, read its contents, and name it based on what is inside. If you have a folder of scanned PDFs called scan0047.pdf and scan0048.pdf and you want them named after the invoice number or the vendor printed on the page, no Linux rename command can do that. Reading a scanned document requires optical character recognition, which is a different job from string manipulation. The CLI tools here are the right answer for pattern-based renaming and the wrong tool entirely for content-based renaming.

Where Renamer.ai Fits (and Where It Does Not)

To be honest about the boundary: renamer.ai is a content-based renamer that reads what is inside a document, the vendor, the invoice number, the date, and names the file from that, but it runs on Windows and Mac, not as a Linux CLI tool. If you are on Linux and need to rename by pattern, the commands on this page are exactly what you want and renamer.ai is not the right fit for that machine. It solves the OCR problem described just above, not the pattern-renaming problem this reference is about. For the full landscape of pattern-based and content-based options across platforms, the bulk rename software hub lays out where each approach belongs.

Frequently Asked Questions

How do I bulk rename files on Linux?

Pick a tool that matches the job. For a regex change use the Perl rename, as in rename 's/ /_/g' * to turn spaces into underscores. For a simple literal swap use the util-linux rename with positional arguments, use mmv for complex wildcard mappings, use zmv in zsh, or fall back to a for loop calling mv. Always preview with a dry run before you commit.

How do I know which rename command my system has (Perl vs util-linux)?

Run rename --version and read the first line. If it mentions util-linux, you have the positional version that takes plain from-text and to-text arguments. If it mentions Perl (or the command behaves like prename), you have the regex version that accepts a Perl substitution such as 's/old/new/'. Debian and Ubuntu commonly ship the Perl one; Fedora and CentOS commonly ship util-linux.

How do I do a dry run before renaming on Linux?

Use the preview flag for your tool. The Perl rename supports rename -n, which prints every rename it would perform without changing anything. zmv supports zmv -n the same way. With a for loop, put echo in front of the mv command so it prints the moves instead of running them. Read the preview, confirm it is correct, then rerun without the -n or echo.

What is the best Linux tool to batch rename files?

There is no single best tool; it depends on the mapping. The Perl rename is best for regex and case changes, util-linux rename for simple literal swaps, mmv for complex wildcard-to-wildcard mappings, and zmv for anyone working in zsh. A for loop with mv is the universal fallback that works even when nothing else is installed.

How do I rename files by regex on Linux?

Use the Perl version of rename, which takes a Perl substitution expression. For example, rename 's/ /_/g' * replaces every space with an underscore, and rename 's/\.JPEG$/.jpg/' * rewrites the extension. Preview first with rename -n, then run the same command without -n. If your system only has util-linux rename, it does not support regex, so use mmv, zmv, or a for loop instead.