mv looks trivial until it silently overwrites a file, because it never asks first by default. This guide builds a repeatable way to rename files, move several into a directory, and stop an important destination from vanishing by accident. The examples use GNU mv from coreutils 9.4, package version 9.4-3ubuntu6.3.
Allow about ten minutes. You need a shell and two paths that you can safely change. This guide uses ordinary user permissions. Use elevated privileges only when the source or destination is not writable by your account; sudo mv does not make a risky destination safe.
Confirm which executable your shell will run and record its version. These are read-only checks:
$ command -v mv
/usr/bin/mv
$ mv --version
mv (GNU coreutils) 9.4
The command has two main forms. mv SOURCE DEST renames one source or moves it to a destination path. mv SOURCE... DIRECTORY moves every listed source into an existing directory. A destination that already names a directory is treated as a directory, which is a common source of surprises when a path is mistyped.
Checkpoint: write down the exact source and destination paths before changing either. Use ls -ld -- PATH to inspect a path without trusting your assumptions:
$ ls -ld -- /path/to/source /path/to/destination
Renaming within one directory changes the directory entry. The file contents are not rewritten in the normal case:
$ mv --verbose -- /path/to/report.txt /path/to/report-final.txt
renamed '/path/to/report.txt' -> '/path/to/report-final.txt'
$ test -f /path/to/report-final.txt && echo 'new name exists'
new name exists
$ test ! -e /path/to/report.txt && echo 'old name is gone'
old name is gone
--verbose prints what was done. The -- marks the end of options, so a path beginning with a hyphen is treated as a path rather than another option. Prefer an absolute path or one beginning with ./ when handling names supplied by another person or program.
Undo this example by moving the renamed file back, provided the old name has not been reused:
$ mv -- /path/to/report-final.txt /path/to/report.txt
For several sources, the final argument must be a directory. Create it first if that is part of your intended change, then inspect it before moving anything:
$ mkdir -p -- /path/to/archive
$ ls -ld -- /path/to/archive
drwxr-xr-x 2 user user 4096 ... /path/to/archive
$ mv --verbose -- /path/to/report-final.txt /path/to/notes.txt /path/to/archive/
renamed '/path/to/report-final.txt' -> '/path/to/archive/report-final.txt'
renamed '/path/to/notes.txt' -> '/path/to/archive/notes.txt'
$ ls -l -- /path/to/archive/
This operation changes the locations of the sources. To undo it, move each file back to its original path while the original parent directory still exists. If a destination file already exists, the default operation can replace it, which is why a plain multi-file command should not be your first move in an unfamiliar directory.
Warning: Without a protection option, GNU mv can replace an existing destination. Use --no-clobber when preserving the destination matters:
$ mv --no-clobber --verbose -- /path/to/incoming.txt /path/to/current.txt
mv: not replacing '/path/to/current.txt'
$ printf 'exit status: %s\n' "$?"
exit status: 1
$ test -f /path/to/incoming.txt && echo 'source remains'
source remains
A skipped file is still a decision worth checking. The command returns a non-zero status in this case, so a script must handle it rather than assume every source moved. If you deliberately want an overwrite prompt instead, use --interactive: it asks before replacing a destination, so answer only after checking both paths.
Do not combine --no-clobber, --interactive and --force casually. If more than one is supplied, only the final one takes effect, so the order in the command line changes the safety behaviour.
For synchronisation-style work, --update=older replaces an existing destination only when it is older than the corresponding source. It is the default mode selected by --update:
$ mv --update=older --verbose -- /path/to/newer-report.txt /path/to/report.txt
$ printf 'exit status: %s\n' "$?"
exit status: 0
With --update=older, a destination that is the same age or newer is left in place. The command may print no verbose line for a skipped source, so verify the timestamps and contents if the result matters:
$ stat --format='source: %y' /path/to/newer-report.txt
source: 2026-09-25 10:15:00.000000000 +0000
$ stat --format='destination: %y' /path/to/report.txt
destination: 2026-09-25 10:10:00.000000000 +0000
The other explicit modes are --update=all, which replaces existing destinations, and --update=none, which skips existing destinations without treating the skip as a failure. Do not use timestamps as a substitute for content comparison when clock accuracy or file contents are uncertain.
Warning: A move is a state change, and a replacement can make recovery harder. When you need the new file at the destination but want the old one retained, use --backup:
$ mv --backup --verbose -- /path/to/revised.txt /path/to/report.txt
renamed '/path/to/revised.txt' -> '/path/to/report.txt' (backup: '/path/to/report.txt~')
$ ls -l -- /path/to/report.txt /path/to/report.txt~
The normal backup suffix is ~. Set a different suffix with --suffix=.bak, or choose numbered backups with --backup=numbered. The backup is another file that must be protected and eventually reviewed. Restore it only after checking that the destination is the file you intend to replace:
$ mv --interactive -- /path/to/report.txt~ /path/to/report.txt
mv: overwrite '/path/to/report.txt'? y
Do not remove the backup as part of an unreviewed batch. Deleting it is irreversible unless another copy exists.
First check whether the source still exists and whether the destination is a directory:
$ ls -ld -- /path/to/source /path/to/destination
$ test -r /path/to/source && echo 'source is readable'
$ test -d /path/to/destination && echo 'destination is a directory'
A missing source, an unwritable parent directory, or a destination that is unexpectedly a directory can each change the result. Read the complete diagnostic before retrying. A move between file systems may be implemented as a copy followed by removal, so a failure after copying can leave both paths or a partial destination behind. Check both paths and compare contents before taking another action.
For a dry inspection of the paths, use ls and stat; there is no general dry-run mode in the installed mv. --debug implies --verbose and explains how a file is copied, which can help when a rename is not possible:
$ mv --debug --no-clobber -- /path/to/source /path/to/destination
The exact diagnostic depends on the paths, permissions and file systems. Treat a non-zero status as unfinished work until you have inspected the source and destination.
--verbose and verified the resulting location.--no-clobber, --interactive or --backup when an existing destination needed protection.