Skip to content
Go back

Bulk File Renaming on Linux: rename, vidir, fd

By SumGuy 6 min read
Bulk File Renaming on Linux: rename, vidir, fd

The mv Loop Gets Old Fast

You’ve been there. Three files to rename — no problem, just mv them one at a time. But somewhere around file twelve, you realize you’re doing something a computer was literally built for, and you’re doing it manually like a cursed goblin.

Terminal window
# Fine for 3 files. Miserable for 300.
mv old_report_1.txt new_report_1.txt
mv old_report_2.txt new_report_2.txt
# ... kill me

Linux has several proper tools for bulk renaming. Which one to reach for depends on whether you want regex power, visual editing, or glob patterns. Here’s the breakdown.


rename — Regex Renaming (the Perl One)

The rename command on Debian/Ubuntu systems is Perl-based and takes a Perl substitution expression. It’s the heavy hitter for pattern-based renames.

Terminal window
# Install on Debian/Ubuntu
sudo apt install rename
# Basic usage: replace 'foo' with 'bar' in all .txt filenames
rename 's/foo/bar/g' *.txt
# Always dry-run first — see what would happen without doing it
rename -n 's/foo/bar/g' *.txt

Common patterns you’ll actually use:

Terminal window
# Lowercase all filenames
rename 's/\(.*\)/\L$1/' *
# Replace spaces with underscores
rename 's/ /_/g' *
# Change extension from .jpeg to .jpg
rename 's/\.jpeg$/.jpg/' *.jpeg
# Add a prefix to all files
rename 's/^/2024-/' *.txt
# Strip a prefix
rename 's/^IMG_//' *.jpg
# Recursive rename (using find to feed it)
find . -name "* *" -exec rename 's/ /_/g' {} +

Wait, Which rename Do You Have?

Here’s the annoying part: there are two rename commands. The Perl version (above) and a simpler util-linux version on some systems. Check which you have:

Terminal window
rename --version

If you see util-linux, the syntax is completely different — it takes a fixed string substitution, not regex: rename old new files. The Perl version will say something like rename from util-linux or show a version string from the rename Perl package.

On Fedora/RHEL, the Perl version is called prename. On Arch it’s available as perl-rename. Worth knowing before you copy-paste a regex from Stack Overflow and wonder why nothing happened.


vidir — Edit Filenames Like a Text File

This one is genuinely underrated. vidir (from the moreutils package) dumps all filenames into your $EDITOR, you edit them however you want, save and quit, and it renames everything accordingly.

Terminal window
sudo apt install moreutils
# Rename files in current directory
vidir
# Rename specific files
ls *.jpg | vidir -
# Rename recursively (careful)
find . -type f | vidir -

What opens is something like:

1 ./IMG_001.jpg
2 ./IMG_002.jpg
3 ./IMG_003.jpg

Change the names on the right side. Delete a line entirely to delete that file. Reorder lines — vidir handles it. Save, quit, done.

This is hands-down the best tool when you have a complex rename you want to think about. You can use all your editor tricks — multi-cursor, regex replace across the buffer, whatever. Nothing changes until you save. Close without saving and nothing happens at all.

Use this for: renaming a batch of photos after a trip, reorganizing project files, any rename where you want human eyes on each decision.


mmv — Glob-Based Mass Rename

mmv (mass move) uses shell glob patterns with numbered back-references. Less common but handy when you’re thinking in glob terms rather than regex.

Terminal window
sudo apt install mmv
# Rename all .txt files to .bak
mmv '*.txt' '#1.bak'
# Add a prefix
mmv '*.jpg' 'vacation_#1.jpg'
# Change double extension
mmv '*.tar.gz' '#1.tgz'

The #1 refers to what matched the first *. It’s not as powerful as Perl regex but the syntax is more readable for simple transformations.


fd + -x — Find and Rename in One Shot

fd is the modern find replacement, and its -x flag executes a command per result with some nice placeholder variables.

Terminal window
sudo apt install fd-find
# On some systems it's 'fdfind', alias it: alias fd=fdfind
# Change .jpeg to .jpg for all files recursively
fd --extension jpeg -x mv {} {.}.jpg
# Remove spaces from filenames found recursively
fd --regex ' ' -x bash -c 'mv "$1" "${1// /_}"' _ {}

Placeholders: {} is the full path, {.} strips the extension, {/} is the filename only, {//} is the parent directory. The -x flag handles filenames with spaces safely — no quoting headaches.


zmv — zsh Users, You Have This Already

If you’re on zsh, zmv is built in (load it with autoload -U zmv). It uses zsh’s extended glob syntax.

Terminal window
autoload -U zmv
# Change extension
zmv '(*).txt' '$1.md'
# Add prefix
zmv '(*).jpg' 'photo_$1.jpg'
# Dry-run
zmv -n '(*).txt' '$1.md'

It’s not installed separately — it’s just there waiting. Nice when you’re already in zsh and don’t want to install anything.


Practical Scenarios

Rename 500 Photos to a Consistent Format

You’ve got IMG_0001.jpg through IMG_0500.jpg and want 2024-01-0001.jpg etc:

Terminal window
rename 's/IMG_/2024-01-/' IMG_*.jpg

For more complex date-based renaming with exiftool:

Terminal window
# Rename by EXIF date — different tool but worth knowing
exiftool '-FileName<DateTimeOriginal' -d '%Y-%m-%d_%H%M%S.%%e' *.jpg

Remove Spaces from Filenames Recursively

Classic problem. Two approaches:

Terminal window
# Using find + rename (Perl version)
find . -name "* *" -exec rename 's/ /_/g' {} +
# Using fd
fd --regex ' ' -x bash -c 'mv "$1" "${1// /_}"' _ {}

Change Extension for All Files in a Directory

Terminal window
# rename (Perl)
rename 's/\.txt$/.md/' *.txt
# Pure bash (no extra tools needed)
for f in *.txt; do mv "$f" "${f%.txt}.md"; done

Complex Rename You Want to Review

Terminal window
vidir

Open it, take your time, edit like a document, save when you’re confident.


Quick Reference

ToolBest ForInstall
rename (Perl)Regex-based renames, extensions, prefixesapt install rename
vidirVisual/manual review, complex batchesapt install moreutils
mmvGlob patterns with back-referencesapt install mmv
fd -xFind + rename pipeline, recursive opsapt install fd-find
zmvzsh users, already availableautoload -U zmv
for loopSimple, no deps, 5-10 filesBuilt-in bash

The right tool depends on the job. Regex substitution across 500 files? rename. Batch of photos you want to manually review? vidir. Already in a fd pipeline? Use -x. Already in zsh? zmv is sitting right there.

Dry-run everything first. rename -n shows you what would happen. vidir shows you the changes before you save. mmv has a -n flag too. Your future self — the one who has to explain to a client why all their files are now named undefined — will thank you.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it may appear here.


Previous Post
Terraform vs Pulumi: Infrastructure as Code Without the YAML Nightmares
Next Post
Nginx Proxy Manager for Normal Humans

Related Posts