Bulk & Automation

Rename Multiple Files in Linux From the Terminal

Linux gives you several ways to rename files in bulk, and the right one depends on how complex the change is. A simple loop with mv covers straightforward cases; find handles files scattered across subdirectories; and the rename utility, with full Perl-compatible regular expressions, does the heavy pattern work. This is the complete command-line reference, with the dry-run flags that let you preview every change before it touches a single file.

Which Linux Command to Reach For

Pick by how the new names relate to the old ones and where the files live.

ToolBest forRegex?
mv in a for loopSimple, predictable renames in one directoryNo, shell patterns only
find -execFiles spread across subdirectoriesVia the command you exec
rename (Perl version)Pattern and regex substitutionYes, full Perl regex
mmvWildcard pattern-to-pattern renamesWildcards, not full regex
zmv (zsh)Powerful renames for zsh usersYes

Method 1: A for Loop With mv

The most portable approach uses the shell you already have. A for loop iterates over the matching files and mv renames each one. To add a prefix to every .txt file: for f in *.txt; do mv -- "$f" "2025_$f"; done. To change an extension, strip the old one with parameter expansion: for f in *.jpeg; do mv -- "$f" "${f%.jpeg}.jpg"; done, where ${f%.jpeg} removes the trailing .jpeg.

Always quote "$f" and use the -- separator so filenames with spaces or leading dashes don't break the command. The loop is limited to shell globbing rather than regex, but for prefixes, suffixes, and extension swaps it's the simplest thing that works, and it needs nothing installed.

You can also add a sequential counter inside the loop to number files as you rename them. A common pattern is i=1; for f in *.jpg; do mv -- "$f" "photo_$(printf '%03d' "$i").jpg"; i=$((i+1)); done, which produces photo_001.jpg, photo_002.jpg, and so on. The printf '%03d' part zero-pads the number so the names sort correctly in a file manager. Because the glob expands in alphabetical order, the files are numbered in that same order, so sort the batch the way you want before you run the loop.

Method 2: find -exec for Files in Subdirectories

When the files aren't all in one folder, find locates them recursively and runs a rename on each. To lowercase-prefix every .log file in a tree: find . -type f -name '*.log' -exec sh -c 'mv "$1" "$(dirname "$1")/archived_$(basename "$1")"' _ {} \;. That looks dense, but the shape is standard: find selects, -exec runs a small shell command per file, and {} is the current path.

For heavy batches, piping find into xargs is faster than spawning a process per file. The key point is that find is how you reach files across a whole directory tree, which a plain glob in one folder can't do.

When filenames may contain spaces or newlines, pair find -print0 with xargs -0 so the two agree on a null byte as the separator instead of whitespace: find . -type f -name '*.log' -print0 | xargs -0 rename 's/^/archived_/'. This safely feeds the whole list to a single rename call. If you only need to touch files in the current directory and one level down, add -maxdepth to find so it doesn't descend into every nested folder.

Method 3: The rename Utility (Regex Power)

The rename command is purpose-built for bulk renaming, and the Perl-based version (default on Debian and Ubuntu, installable elsewhere) accepts a full regular expression. This is where Linux out-muscles simple loops:

  1. Preview first with -n (dry run): rename -n 's/ /_/g' *.txt prints what would change without doing it.
  2. Replace spaces with underscores: rename 's/ /_/g' *.txt
  3. Strip a prefix: rename 's/^IMG_//' *.jpg
  4. Change an extension: rename 's/\.jpeg$/.jpg/' *.jpeg
  5. Reorder a captured date: rename 's/(\d{4})-(\d{2})-(\d{2})/$3-$2-$1/' *.pdf

Note that some distributions ship the simpler util-linux rename, which does literal from-to substitution rather than regex (rename .jpeg .jpg *.jpeg). Check which you have with rename --version, and install the Perl version (often the rename or perl-rename package) if you need regular expressions.

Method 4: mmv and zmv for Pattern Renames

mmv renames by matching a wildcard pattern and mapping it to another: mmv '*.txt' '#1.bak' renames every .txt to .bak, where #1 refers to the first wildcard. It's concise for pattern-to-pattern jobs once installed. And for zsh users, zmv (load it with autoload -U zmv) offers similarly powerful renaming with regex-like matching built into the shell, zmv '(*).txt' '${1}_backup.txt' is a common form. Both are optional power tools; the mv loop and the rename utility cover the vast majority of real needs.

The One Thing the Terminal Can't Do: Read the File

Every command here works on the filename and the path. None of them can read what's inside a document. If you have a directory of scanned PDFs named scan001.pdf through scan847.pdf and you want each named for the invoice number or contract parties printed inside, no rename regex can produce that, because the information isn't in the filename to match against.

Naming a file by its content requires OCR to read the page and logic to identify the fields, which is a different category of tool called content-aware renaming. It's worth knowing the boundary: the terminal is the right, free tool when the new name is a transformation of the old one or a pattern you can express, and it simply can't help when the correct name lives inside the document. For that content-based approach, see the bulk rename software overview.

In practice, most Linux bulk-rename tasks are genuinely pattern jobs, prefixes, extensions, cleanups, so the commands above are all you need; reach past them only when the filename is meaningless and the file's contents are the only source of the right name.

Renaming on Other Systems

These commands are Linux-specific and don't carry over to Windows, which uses PowerShell or CMD instead. If you also work across systems, the bulk rename software hub links to the Windows and Mac methods. Renamer.ai's content-aware renaming, mentioned above, runs on Windows and Mac rather than Linux, so on Linux the terminal remains your tool of choice for filename-based work.

Frequently Asked Questions

How do I rename multiple files at once in Linux?

Use a for loop with mv for simple cases (for f in *.txt; do mv -- "$f" "2025_$f"; done), or the rename utility for pattern-based changes (rename 's/ /_/g' *.txt). Preview a rename batch with rename -n before applying it.

How do I do a regex rename in Linux?

Use the Perl-based rename utility, which takes a full regular expression: rename 's/^IMG_//' *.jpg strips a prefix, and rename 's/(\d{4})-(\d{2})-(\d{2})/$3-$2-$1/' *.pdf reorders a date. Check with rename --version that you have the Perl version, not util-linux.

How do I rename files in subdirectories?

Use find to locate them recursively and run a rename on each: find . -type f -name '*.log' -exec sh -c 'mv "$1" ...' _ {} \;. A plain shell glob only sees one directory, so find is how you reach a whole tree.

What's the difference between the two rename commands?

There are two: the Perl-based rename (Debian/Ubuntu default) takes regular expressions, while the util-linux rename does simple literal from-to substitution (rename .jpeg .jpg *.jpeg). Run rename --version to see which you have and install the Perl one if you need regex.

How do I preview a rename before running it?

With the Perl-based rename utility, add the -n flag for a dry run: rename -n 's/ /_/g' *.txt prints each old name and the name it would become without changing anything on disk. Read that output carefully, and only when it looks right rerun the exact same command without -n. For a for loop, put echo in front of mv (echo mv -- "$f" "2025_$f") to print the commands first, then remove echo to apply them.

How do I handle filenames with spaces in Linux?

Quote every variable that holds a filename and use the -- separator so a name that starts with a dash isn't read as an option: mv -- "$old" "$new". When piping from find, use find -print0 with xargs -0 so a space or newline in a name doesn't split it into two arguments. The rename utility handles spaces in its arguments cleanly, which is one reason it is safer than hand-built loops for messy batches.

Can Linux rename files based on their content?

The standard terminal tools cannot, they work on filenames and paths, not the document inside. Naming a scanned file by what's printed in it needs content-aware OCR renaming, which is a separate kind of tool and, in renamer.ai's case, runs on Windows and Mac rather than Linux.