mv moves files and directories, and it’s also how you rename them. Linux has no separate rename command for single files. Renaming is just moving to a new name in the same place.
mv [options] SOURCE DEST
mv [options] SOURCE... DIRECTORY
Rename a file or directory
mv report.txt report-2026.txt
mv old-project new-project
Directories don’t need -r with mv, unlike cp and rm.
Move files
mv report.txt ~/archive/ # into a directory, keeps the name
mv report.txt ~/archive/q3-report.txt # move and rename at once
mv *.log /var/log/old/ # many files with a glob
mv a.txt b.txt c.txt /srv/files/
When there is more than one source, the last argument must be an existing directory.
Moving a directory into an existing directory
mv site /var/www/
- If
/var/www/sitedoesn’t exist,sitebecomes/var/www/site. - If
/var/www/sitealready exists and is empty, it gets replaced. - If it exists and isn’t empty,
mvfails with “Directory not empty”. It won’t merge directories. To merge, usersync -a src/ dest/and then remove the source, orcp -aand thenrm.
Avoid overwriting files
By default, mv silently overwrites an existing destination file. Use these options to protect yourself:
mv -i file dest # ask before overwriting
mv -n file dest # never overwrite (no-clobber)
mv -u file dest # only move if the source is newer
mv --backup=numbered file dest # keep the old dest as dest.~1~
mv -b file dest # simple backup: dest~
In scripts, -n is a safe default when collisions are possible. -v (verbose) prints each move:
mv -v *.jpg photos/
Same filesystem vs another filesystem
Within one filesystem, mv just renames a directory entry. It’s instant even for huge files, and ownership and permissions don’t change.
Across filesystems (another disk, partition or mount), mv copies and then deletes. That takes time, and if it’s interrupted you may end up with a partial copy. For large moves to another disk, it’s safer to use:
rsync -a --remove-source-files /data/old/ /mnt/new/
and then remove the empty directories. See rsync examples.
Files with awkward names
mv -- -weird-name.txt normal.txt # names starting with a dash
mv "my file.txt" my-file.txt # spaces: quote the name
mv my\ file.txt my-file.txt # or escape the space
-- tells mv that options have ended.
Bulk renaming
A loop in Bash:
# change .jpeg to .jpg
for f in *.jpeg; do mv -n -- "$f" "${f%.jpeg}.jpg"; done
# add a prefix
for f in *.png; do mv -n -- "$f" "2026-$f"; done
# replace spaces with dashes
for f in *\ *; do mv -n -- "$f" "${f// /-}"; done
For more complex patterns, use the rename utility. On Debian/Ubuntu, apt install rename gives the Perl version:
rename -n 's/\.jpeg$/.jpg/' *.jpeg # -n = dry run, shows what would happen
rename 's/\.jpeg$/.jpg/' *.jpeg
rename 'y/A-Z/a-z/' * # lowercase filenames
Always run with -n first. Note that RHEL’s rename is a different, simpler tool (rename .jpeg .jpg *.jpeg).
Moving files a service uses
- Log files: if you
mva log that a process is writing to, the process keeps writing to the moved file, because it has the file open. That’s how log rotation works. Signal or reload the service so it reopens the log. - Web roots and configs: moving files keeps their ownership, but with SELinux the security label comes along too. Run
restorecon -Rafter moving files into web directories on RHEL-family systems.
Common mistakes
- Typo in the destination directory:
mv file /srv/filsrenamesfileto/srv/filsinstead of moving it into/srv/files/. Add a trailing slash, as inmv file /srv/files/. Thenmvfails if the directory doesn’t exist. - Overwriting by accident, for example
mv config.php config.php.bakwhen the.bakalready held the only good copy. Use-ior-n. - Globs that match nothing:
mv *.tmp old/with no.tmpfiles fails with “cannot stat ‘*.tmp’”. That’s harmless, but scripts should handle it.
Quick reference
| Task | Command |
|---|---|
| Rename | mv old new |
| Move into dir | mv file dir/ |
| Ask before overwrite | mv -i |
| Never overwrite | mv -n |
| Verbose | mv -v |
| Keep backup of target | mv --backup=numbered |
| Bulk rename | rename -n 's/a/b/' * |