Skip to main content

How to Batch Rename Files Safely With a Reviewable Plan

Plan a bulk rename before you touch a single file: build patterns with sequence numbers and tokens, normalize case and slugs, then preview the mv commands to avoid collisions.

Published By Li Lei
#batch rename #rename files #file management #kebab case #shell commands

How to Batch Rename Files Safely With a Reviewable Plan

The fastest way to lose a folder of files is to rename them in a hurry. You select a hundred photos, type a clever new pattern, hit apply, and three of them quietly overwrite each other because two source names mapped to the same target. There is no undo on a destructive mv. The fix is not to rename more carefully by hand; it is to plan the whole operation first, look at it, and only then run it.

That is the exact job of the Batch File Rename Planner. It reads your filenames locally, applies the rename pattern and normalization rules you choose, and hands back a table: original name, proposed new name, and the shell mv command for each row. Nothing is uploaded, nothing is renamed. You get a plan you can read, sanity-check, and run outside the browser.

Why a plan beats renaming in place

A rename feels atomic in your head, but on disk it is a sequence of moves, and order matters. If IMG_2207.JPG becomes 02-sunset.jpg while IMG_2210.JPG also becomes 02-sunset.jpg, the second move clobbers the first. You end up with one file where you expected two, and the lost one is gone.

When the rename is a static plan instead of a live action, every one of these problems becomes visible before it happens. You can see two rows pointing at the same target. You can see a name that turned into an empty string or a trailing dot. You can see that your sequence numbers skipped from 9 to 100 because you forgot to zero-pad. Reading is cheap; recovering deleted files is not.

Patterns with sequence numbers and tokens

The core of any rename is the pattern. A pattern is a template made of literal text plus tokens that get filled in per file. The planner supports three:

  • {{n}} — the sequence number, counting through the batch in order
  • {{name}} — the original base filename, without its extension
  • {{ext}} — the original extension

So a pattern like {{n}}-{{name}} turns Beach Day.jpg into 1-Beach Day.jpg, then Boat.jpg into 2-Boat.jpg, and so on. You can mix tokens with fixed prefixes too: invoice-2026-{{n}}.{{ext}} produces invoice-2026-1.pdf, invoice-2026-2.pdf. The literal parts are yours; the tokens carry the per-file data.

Tokens compose with normalization, which is where the plan earns its keep. A pattern decides the shape of the name; the case and slug rules decide how the variable parts get cleaned. Together they let you go from a messy human-named folder to a tidy, predictable, machine-friendly scheme in one pass.

Case and slug normalization

Raw filenames are full of things that break later: spaces, mixed case, accented characters, stray punctuation. The planner offers five normalization modes for the name part:

  • Keep — leave the name as it is
  • lowercase — fold everything down
  • UPPERCASE — fold everything up
  • kebab-case — lowercase words joined by hyphens, Beach Day to beach-day
  • snake_case — lowercase words joined by underscores, Beach Day to beach_day

For anything that touches a URL, a CMS slug, or a static site, kebab-case is the safe default. My Vacation Photo (2).JPG becomes my-vacation-photo-2.jpg: no spaces to encode, no capitals to mismatch, no parentheses to escape. snake_case is the better fit when the names feed code or data pipelines that prefer underscores. The point is that you pick the rule once and it applies uniformly, instead of you hand-editing a hundred names and introducing a hundred small inconsistencies.

A worked example: a folder of trip photos

Here is the case I run most often. I came back from a trip with a camera dump full of names like DSC09841.JPG, IMG-20260601-WA0007.jpeg, and Sunset over the bay.JPG — inconsistent casing, inconsistent extensions, spaces everywhere. I wanted a single numbered, slugified set I could drop straight into a gallery.

I loaded the folder into the planner, set the pattern to {{n}}-{{name}}.{{ext}}, and chose kebab-case for the case mode. The plan came back like this:

original                       new                          status   command
DSC09841.JPG                   1-dsc09841.jpg               ok       mv -n -- "DSC09841.JPG" "1-dsc09841.jpg"
IMG-20260601-WA0007.jpeg       2-img-20260601-wa0007.jpeg   ok       mv -n -- "IMG-20260601-WA0007.jpeg" "2-img-20260601-wa0007.jpeg"
Sunset over the bay.JPG        3-sunset-over-the-bay.jpg    ok       mv -n -- "Sunset over the bay.JPG" "3-sunset-over-the-bay.jpg"

Three things to notice. The sequence number gives each file a stable, ordered prefix. The extensions got folded to lowercase so .JPG and .jpeg stop looking like two different formats to a case-sensitive web server. And the mv -n flag means "no clobber": even if I missed a collision, the move refuses to overwrite an existing target instead of silently destroying it. I scanned the status column, saw every row marked ok with no duplicate-target flags, and only then pasted the commands into a terminal in the right directory.

When I do want to clean up the content of files rather than their names — stripping trailing whitespace or normalizing line endings in a batch of text exports — I reach for the Text File Cleaner instead, and keep the rename planner strictly for the names.

Preview the commands, avoid the collisions

The status column is the safety net. The planner checks each proposed target against the others in the batch and flags trouble before you ever run anything:

  • duplicate-target — two source files would land on the same new name. Fix the pattern (usually by adding {{n}} or padding it) before running.
  • invalid-target — the result is empty, ends in a stray dot, or contains characters the filesystem rejects.
  • no-op — the new name equals the old one, so the command is skipped.

Two more habits make this airtight. First, read the actual mv commands, not just the new-name column; the command is what runs, and seeing mv -n -- "old" "new" confirms the no-clobber guard and the -- that stops a filename starting with a dash from being read as a flag. Second, run the commands only in the directory you planned them for. The plan uses bare filenames, so executing it in the wrong folder either fails loudly or, worse, matches files you did not mean to touch.

A subtle case worth flagging: on macOS and Windows, the filesystem treats Photo.JPG and photo.jpg as the same file. If your normalization produces a target that differs from an existing file only by case, that is a real collision even though the strings look different. Skim the plan with that in mind, and when in doubt, add a sequence number so every target is unique by construction.

Make it a routine

Bulk renames stop being scary once you separate planning from doing. Build the pattern, pick the case rule, generate the plan, read the table, run the commands. The browser never touches your disk; you stay in full control of the destructive step. Try it on your next messy folder with the Batch File Rename Planner and keep the CSV as a record of exactly what changed.


Made by Toolora · Updated 2026-06-13