Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

58 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ren

ren is a fast bulk file renamer, sibling of rep.

Where rep rewrites file contents, ren rewrites file names. Plain and regex find/replace, smart preserve-case rewrites, an interactive preview, glob filters, listing, and multiple -e/--expression rewrites in a single pass.

ren is dry-run by default - every invocation prints the plan and exits. Pass -W (or --write) when you're ready to actually rename.

Install

macOS / Linux

brew install gechr/tap/ren

Windows

scoop bucket add gechr https://github.com/gechr/scoop-bucket
scoop install gechr/ren

Cargo

cargo install --git https://github.com/gechr/ren

Usage

help

Examples

Examples below show the plan - add -W to commit.

# Replace `foo` with `bar` anywhere in basenames (cwd, files only)
ren foo bar

# Same, but actually rename
ren -W foo bar

# Recurse into subdirectories
ren -R foo bar

# Also rename matching directories
ren --include-dirs foo bar

# Restrict to .rs files
ren -f rs old new

# Stem-only matching is the default (api_v1.json -> api_v2.json)
ren v1 v2

# Include extensions in matching and replacement
ren -x rs txt

# Match only the extension; preserve the stem (foo.rs -> foo.txt)
ren -X rs txt

# Rename and change the extension in one pass (img_a.jpg, img_b.jpg -> 1.png, 2.png)
ren -W -s '{n}' -E png

# Smart-rename across case variants
#   foo_bar -> hello_world, FooBar -> HelloWorld, FOO_BAR -> HELLO_WORLD, …
ren --smart foo_bar hello_world

# Regex rename: replace test_ prefix with spec_
ren --regex '^test_' 'spec_'

# Interactive preview: walks each entry and applies the accepted ones
ren --preview foo bar

# Apply multiple replacements in a single pass
ren -W -e foo bar -e baz qux

# Print matching paths only (no rename)
ren -l foo

# Case-only rename (works on case-insensitive filesystems too)
ren -W tmp TMP

# Number every file in cwd: 01_alpha.txt, 02_beta.txt, … (smart per-dir width)
ren --prepend '{N}_'

# Custom counter format with explicit zero-padding and a path scope
ren --prepend='{n:03}_' src/

# Number files as a suffix on the stem: foo.txt -> foo-1.txt, …
ren --append '-{n}'

# Replace each name outright: 01.jpg, 02.jpg, … (extension preserved)
ren --supplant '{n:02}'

# Lowercase every basename in cwd
ren --lower

# Compose: find/replace, then lowercase, then append, then prepend
ren --prepend '{N}_' --lower foo bar

Transforms

When <find> <replace> alone isn't enough, transforms layer over the find/replace stage. They're optional, compose with each other, and make <find> <replace> itself optional too - so ren --prepend '{N}_' is a valid invocation.

Flag Effect
-L, --lower lowercase the basename (mutex with --upper)
-U, --upper uppercase the basename
-P, --prepend <fmt> prepend a literal string or template
-A, --append <fmt> append a literal string or template
-s, --supplant <fmt> replace the name with a literal string or template (extension preserved unless combined with -x)
-E, --change-extension <ext> change, add, or strip the file extension (composes with the stem pipeline; mutex with -x/-X)

Counter templates (recognised inside --prepend, --append, and --supplant):

  • {n} - the 1-based per-parent-directory index (1, 2, 3, …).
  • {n:0WIDTH} - zero-padded to WIDTH digits ({n:03} β†’ 001, 002, …).
  • {N} - smart-width: zero-padded to max(2, len(dir_count)). So a directory with under 100 entries gets 01, 02, …; 100+ gets 001, 002, …; 1000+ gets 0001, 0002, …. Pick this when you don't want to count by hand.

Anything else in the format string passes through, so [{n:02}]-, chapter-{n:03}_, -{n} all work as written. Both affixes share the same per-record counter, so --prepend '{n}-' --append '-{n}' produces 1-foo-1, 2-bar-2, …. Values that start with - need the =-attached form (e.g. --append='-{n}') so they aren't mistaken for flags.

The pipeline runs in fixed canonical order regardless of argv order:

  1. find/replace (positional or -e)
  2. --supplant
  3. --lower or --upper
  4. --append
  5. --prepend

By default the pipeline runs on the file stem only and the extension is reattached afterward - this prevents accidents like ren txt notes rewriting report.txt to report.notes. -x/--include-extension opts back into matching the full basename, and -X/--only-extension flips the split so the pipeline runs on the extension only and the stem is preserved verbatim. -E/--change-extension <ext> is orthogonal: it overrides the reattached extension while the rest of the pipeline still runs on the stem, so it composes with --supplant and friends (ren -s '{n:02}' -E png β†’ 01.png, 02.png, …). A leading dot is optional, files without an extension gain one, and an empty value (-E '') strips it; the whole extension is replaced, including compound ones (archive.tar.gz β†’ archive.zip). It is mutually exclusive with -x/-X. Counter indexes reset per parent directory - with --recursive, each directory starts at 1 (or 01, 001, … with a width specifier). Files filtered out by find/replace don't consume a counter slot.

Preview keymap

ren --preview walks each plan entry and asks for a decision:

Key Action
y accept this rename
n reject this rename
A accept this and all remaining renames
q stop prompting and apply accepted renames
← go back and revise the previous decision
β†’ skip this rename

Accepted renames are applied immediately - --preview is its own mode and is mutually exclusive with --dry-run/--write.

About

πŸ”€ Batch rename tool

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages