Guides

How to rename a directory in Linux: the mv command for files and folders

How to rename a directory in Linux with mv: rename files and folders, move them into directories, -i, -n and -T, bulk renames, and fixes for mv errors.

Published ~9 min read
On this page

Short answer: to rename a directory in Linux, run mv old_name new_name. The same command renames a file, and mv file dir/ moves a file into a directory. One trap: if new_name is already an existing directory, mv puts old_name inside it instead of renaming it. Add -i to be asked before anything gets overwritten.

any Linux
mv old_name new_name          # rename a directory (or a file), no -r needed
mv report.pdf archive/        # move a file into a directory
mv -i draft.txt final.txt     # ask before overwriting final.txt
mv -T site site-old           # rename only; never move site into an existing site-old

The outputs on this page come from Debian 12 with GNU coreutils 9.1 and bash 5.2.15, run in a scratch directory on 21 October 2026, including rename.ul from util-linux 2.38.1 and rsync 3.2.7. The Perl rename lines follow its man page, and the cross-filesystem behaviour follows the GNU coreutils manual; neither was run here. Ubuntu, Rocky Linux and AlmaLinux ship the same GNU mv.

mv cheat sheet

TaskCommand
Rename a directorymv logs logs-2026
Rename a filemv notes.txt todo.txt
Move a file into a directorymv report.pdf archive/
Move several files into a directorymv *.log archive/
Target directory first (for find and xargs)mv -t archive/ a.log b.log
Ask before overwritingmv -i a.conf b.conf
Never overwritemv -n a.conf b.conf
Keep a backup of what gets overwrittenmv -b a.conf b.conf
Only if the source is newermv -u build/app.js public/app.js
Show what happensmv -v old new
Rename, never move into an existing directorymv -T site site-old
Name that starts with a dashmv -- -draft draft
Name with spacesmv "My Folder" my-folder

How do I rename a directory in Linux?

Give mv the current name and the new one. Unlike cp, it needs no -r for a directory, because nothing is copied: on the same filesystem, mv only changes the name in the parent directory. That is why renaming a directory with thousands of files is instant, and why owner, permissions and timestamps stay exactly as they were.

Example output
$ mv -v old_name new_name
renamed 'old_name' -> 'new_name'
$ ls -R new_name
new_name:
sub

new_name/sub:
a

Paths work too, so mv /srv/app/releases/v1 /srv/app/releases/v1-broken renames a directory without changing into its parent first. Quote names with spaces: mv My Folder new without quotes tries to move two things called My and Folder.

When the new name already exists as a directory

This is where renaming goes wrong. If the second name is an existing directory, mv does not replace it; it moves the first directory into it:

Example output
$ mkdir site site-old
$ mv -v site site-old
renamed 'site' -> 'site-old/site'

Run the same command a day later in a deploy script, after site-old already exists, and you get a nested site-old/site instead of a rename. -T (--no-target-directory) tells mv to treat the second name as the new name and nothing else. It replaces an empty directory and refuses a full one:

Example output
$ mv -Tv site2 empty
renamed 'site2' -> 'empty'
$ mv -T src dst
mv: cannot move 'src' to 'dst': Directory not empty

mv never merges two directories. To combine src into an existing dst, copy with rsync and remove the source afterwards, as shown further down.

Rename a file, and what happens to an existing one

mv notes.txt todo.txt renames a file. If todo.txt already exists, plain mv replaces it without a word, and the old content is gone. Three options protect it:

Example output
$ mv -i a.conf b.conf
mv: overwrite 'b.conf'? n
$ mv -nv a.conf b.conf          # -n: silently skip, b.conf untouched
$ mv -bv a.conf b.conf          # -b: overwrite, keep the old one as b.conf~
renamed 'a.conf' -> 'b.conf' (backup: 'b.conf~')

--backup=numbered keeps every old version instead of only the last one (d.~1~, d.~2~, and so on), and -S .bak changes the suffix of a simple backup from ~ to .bak. On a server, mv -b is a cheap safety net when you put a new config file in place of a working one.

Move files into a directory

When the last argument is an existing directory, mv moves everything before it into that directory and keeps the names. Write the directory with a trailing slash: if it does not exist (a typo), mv then stops instead of renaming your file to the typo:

Example output
$ mv -v *.log archive/
renamed 'a.log' -> 'archive/a.log'
renamed 'b.log' -> 'archive/b.log'
renamed 'c.log' -> 'archive/c.log'
$ mv -v x.txt nodir/
mv: cannot move 'x.txt' to 'nodir/': Not a directory

With more than two names, the last one must be a directory, otherwise mv answers target 'r': Not a directory. -t DIR names the target directory first, which is what find -exec ... + and xargs need, because they append the file names at the end. The find guide explains the + form:

any Linux
# move logs older than 30 days, from anywhere below logs/, into old/
find logs -name '*.log' -mtime +30 -exec mv -v -t old/ {} +

# the same with xargs, safe for names with spaces
find logs -name '*.log' -mtime +30 -print0 | xargs -0 mv -t old/

That is also the fix for Argument list too long, which bash prints when a glob such as mv *.jpg photos/ expands to more names than the kernel accepts in one command line.

mv options: -i, -n, -f, -u, -v

OptionLong formWhat it does
-i--interactiveAsk before overwriting an existing file
-n--no-clobberNever overwrite; skip the file
-f--forceNever ask. Without it, mv still asks before replacing a write-protected file when run in a terminal
-u--updateMove only if the source is newer than the destination, or the destination is missing
-v--verbosePrint each rename
-b--backupKeep the overwritten file as NAME~
-t DIR--target-directory=DIRMove everything into DIR, named first
-T--no-target-directoryTreat the last name as the new name, never as a directory to move into

If you combine -i, -f and -n, the last one wins: mv -f -i asks, mv -i -f does not. That matters because Rocky Linux and AlmaLinux alias mv to mv -i in root’s ~/.bashrc (Debian ships the same line commented out in /usr/share/base-files/dot.bashrc), so mv -f typed at that prompt still overwrites without asking. Scripts never see the alias: bash does not expand aliases in a non-interactive shell.

Rename many files at once

mv renames one thing at a time. For a batch, either loop over the files in bash and build each new name with parameter expansion, or use a rename tool. The loop works on every system with bash and needs nothing installed:

bash
# .jpeg to .jpg
for f in *.jpeg; do mv -v -- "$f" "${f%.jpeg}.jpg"; done

# spaces to underscores
for f in *' '*; do mv -v -- "$f" "${f// /_}"; done

# upper case to lower case (bash 4 and later)
for f in *.TXT; do mv -v -- "$f" "${f,,}"; done

# add a prefix
for f in IMG_*.jpg; do mv -v -- "$f" "2026-10_$f"; done
Example output
renamed 'IMG_001.jpeg' -> 'IMG_001.jpg'
renamed 'IMG_002.jpeg' -> 'IMG_002.jpg'
renamed 'holiday photo.jpeg' -> 'holiday photo.jpg'
ExpansionExampleMeaning
${f%.jpeg}photo.jpeg becomes photoRemove a suffix
${f#IMG_}IMG_001.jpg becomes 001.jpgRemove a prefix
${f// /_}my photo.jpg becomes my_photo.jpgReplace every match
${f,,}README.TXT becomes readme.txtLower case (bash 4 and later)
${f^^}notes.txt becomes NOTES.TXTUpper case (bash 4 and later)

Three habits keep a loop safe. Run it once with echo mv in place of mv to see the commands first. Quote "$f" everywhere, so names with spaces survive. And put -- before the names, so a file called -draft is not read as an option. If no file matches, bash passes the pattern itself (*.png) to the loop; shopt -s nullglob turns that into an empty loop.

rename: two different tools with the same name

On Debian and Ubuntu, the rename package installs the Perl version, which takes a substitution expression. Rocky Linux, AlmaLinux and Fedora ship the util-linux version as rename, which replaces a plain string; Debian has that one as rename.ul. A command written for one fails on the other:

Perl rename · Debian · Ubuntu (apt install rename)
rename -n 's/\.jpeg$/.jpg/' *.jpeg    # -n: show what would happen
rename 's/\.jpeg$/.jpg/' *.jpeg
util-linux rename · Rocky · Alma (rename.ul on Debian)
$ rename.ul -n -v .bak .log *.bak
`log1.bak' -> `log1.log'
`log2.bak' -> `log2.log'
$ rename.ul -v .old .bak *.old
`log1.old' -> `log1.bak'
`log2.old' -> `log2.bak'

The util-linux version replaces the first occurrence of the string anywhere in the name, not only at the end, so check with -n first. For anything more than a suffix swap, the bash loop is easier to read and to review.

Moving across filesystems: copy, then delete

Inside one filesystem, mv calls the rename() system call, and the data never moves. Between two filesystems (another disk, a separate partition, an NFS mount, /tmp on tmpfs), rename is impossible, and per the GNU coreutils manual mv falls back to copying the files and then removing the originals. That changes what you should expect:

  • It takes as long as a copy, and the target filesystem needs room for everything before the source is freed.
  • An interrupted move leaves two halves: the source is removed only after the copy, so a Ctrl+C or a dropped SSH session leaves a partial copy at the destination. Run long moves inside tmux or screen.
  • Checking which filesystem a path is on: df -h /srv/data /mnt/backup; two different lines in the first column mean a copy, not a rename.

For a large move between disks or servers, rsync is the better tool, because it can resume where it stopped and only removes a source file once it is safely copied:

any Linux
rsync -a --remove-source-files src/ dst/     # copy, deleting each file once it is copied
find src -type d -empty -delete              # rsync leaves the empty folders behind

In the test, rsync moved src/a and src/sub/b into dst/ and left src and src/sub as empty folders, which the second line removed.

mv vs cp vs rsync

mvcprsync
Source afterwardsGone (renamed)Still thereStill there, unless --remove-source-files
Same filesystemInstant rename, no data copiedFull copyFull copy, skips unchanged files on a rerun
Directory needs a flagNo-r (or -a)-a
Owner and timestampsKept (same file)New owner and current time unless -a or -pKept with -a
InterruptedSame fs: nothing to interrupt; across fs: partial copyPartial copyRerun continues
Merges into an existing directoryNoYes, with cp -a src/. dst/Yes
Over SSH to another serverNoNo (scp does)Yes

The timestamp row is easy to check: a file moved with mv keeps its inode number and its modification time, while a plain cp of a file dated 1 January 2025 came out with the current time. For copies between servers, see transferring files to a VPS.

mv errors and what they mean

Message ends withMeaningFix
Directory not emptyThe new name is a directory that already has content (with -T, or an existing dir of the same name inside the target)Pick another name, or merge with rsync
Permission deniedNo write and execute permission on the source or the target directorySee below
are the same fileBoth names point to the same file: the same path, ./name, or two hard linksNothing to do; check the paths
a subdirectory of itselfYou tried mv dir dir/childMove it somewhere outside itself
cannot overwrite directory with non-directoryA file would replace a directoryRename or remove the directory first
Not a directoryThe target ends with / but is not a directory, or several sources and the last name is no directorymkdir -p
No such file or directoryThe source does not exist (cannot stat), or the target's parent is missingCheck spelling with ls; create the parent
missing destination file operandOnly one name givenAdd the new name
Argument list too longA glob matched too many filesfind ... -exec mv -t DIR {} +
Device or resource busyPer rename(2): the path is a mount point, or in use as oneUnmount it, or rename inside it instead
Read-only file systemThe filesystem is mounted read-onlyRead-only file system

mv: cannot move: Permission denied

Example output (as an unprivileged user)
mv: cannot move 'rootdir/file' to 'mine/file': Permission denied
mv: cannot move 'rootdir/file' to 'rootdir/file2': Permission denied

A rename changes two directories, not the file: it removes the name from the old parent and adds it to the new one. You need write and execute permission on both parents, and a file’s own mode does not matter. The second line shows it: even renaming a file inside the same root-owned folder failed. Moving a directory to another parent also needs write permission on that directory itself, because its .. entry changes (per rename(2)). Directories with the sticky bit, such as /tmp, add a rule on top: only the file’s owner, the directory’s owner or root may rename or move it out. namei -l /path/to/file lists owner and mode of every directory on the way, and the chmod guide explains what write and execute mean on a directory.

Renaming directories on a live server

On a server, a rename is rarely just a rename: something else usually has the old path written down.

  • Configs keep the old path. Rename /var/www/shop and nginx, PHP-FPM pools, systemd units and crontab lines that name it break at their next reload. Search before you rename: sudo grep -rl /var/www/shop /etc.
  • Running processes do not notice. A program keeps the files it has open and its working directory through a rename, so it may seem fine until it restarts and looks for the old path.
  • Switch releases with a symlink, not a rename. Point a current link at the live release and replace the link, so the web server never sees a half-finished directory. mv -T replaces it in one step, because rename() replaces the old name atomically:
bash
ln -s releases/v2 current.new
mv -Tv current.new current
# renamed 'current.new' -> 'current'

Without -T, mv follows the existing current link to its directory and drops current.new inside the old release, which is exactly what it did in the test (renamed 'current.new' -> 'current/current.new'). Create the folders you move things into with mkdir -p, and before a big reorganisation on a VMHeaven VPS, take a snapshot in the panel: it is the undo that mv itself does not have.

Frequently asked

How do I rename a directory in Linux?

Run mv old_name new_name in the directory that contains it, or use full paths: mv /srv/app/old /srv/app/new. mv needs no -r for a directory. If new_name already exists as a directory, mv moves old_name inside it instead of renaming it; mv -T old_name new_name only ever renames.

Why did mv put my folder inside the other folder instead of renaming it?

Because the new name already existed as a directory, and mv treats an existing directory as the place to move into. mv -T (--no-target-directory) treats the second name strictly as the new name: it replaces an empty directory and stops with Directory not empty if the target has content.

How do I rename many files at once in Linux?

Use a bash loop with parameter expansion, for example: for f in *.jpeg; do mv "$f" "${f%.jpeg}.jpg"; done. Run it with echo mv first to check the names. A rename tool also works, but there are two: the Perl rename on Debian and Ubuntu takes an expression (rename 's/\.jpeg$/.jpg/' *.jpeg), the util-linux rename on Rocky Linux and AlmaLinux takes plain strings (rename .jpeg .jpg *.jpeg).

Does mv work across different disks or partitions?

Yes, but then it is no longer a rename: mv copies the data to the other filesystem and removes the source afterwards. It takes as long as a copy and needs free space on the target. For large moves, rsync -a --remove-source-files is easier to resume after an interruption.

Related articles

All guides