Linux mv Command: The Mechanics of Moving and Renaming Files
Linux mv Command: The Mechanics of Moving and Renaming Files#
2026-05-12 20:17
You use mv every day, but it’s more nuanced than you think. Moving and renaming files are the same operation in Linux — which sounds counterintuitive, but once you grasp this, everything else falls into place.
The Core: Inode Operations#
mv doesn’t actually “transport” data. It operates on directory entries (dentries).
# Rename = dentry modification within the same filesystem
mv old_name.txt new_name.txt
# Move across filesystems = actual data copy
mv /home/user/file.txt /mnt/usb/
Within the same filesystem, mv only modifies the directory entry pointer. The inode number stays the same, data blocks don’t move — it’s instantaneous. Across filesystems, mv performs cp + rm: copy the data first, then delete the source.
You can verify this with strace:
# Same filesystem: only a rename syscall
strace mv file1.txt file2.txt 2>&1 | grep -E "rename|link"
# rename("file1.txt", "file2.txt") = 0
# Cross-device: copy_file_range + unlink
strace mv /home/user/file.txt /mnt/usb/ 2>&1 | grep -E "copy|unlink"
# copy_file_range(3, ...) = 8192
# unlink("/home/user/file.txt") = 0
Common Patterns and Pitfalls#
1. Batch Renaming#
mv itself doesn’t support batch operations, but a for loop does the job:
# Rename all .txt files to .md
for f in *.txt; do
mv "$f" "${f%.txt}.md"
done
If filenames contain spaces, omitting quotes will break things. ${f%.txt} is bash parameter expansion — it strips the shortest .txt match from the end.
For complex batch renames, use the rename command:
# Perl rename with regex support
rename 's/\.txt$/.md/' *.txt
2. Moving Directories#
mv doesn’t need -r for directories, unlike cp:
# Directories move directly, no recursive flag needed
mv mydir/ /target/path/
# cp requires -r
cp -r mydir/ /target/path/
Within the same filesystem, moving a directory only modifies the parent directory’s dentry — no recursive copying involved.
3. Overwrite Confirmation#
By default, mv silently overwrites the target file. Dangerous:
# Interactive mode: confirm before overwriting
mv -i source.txt target.txt
# No-clobber mode: skip if target exists
mv -n source.txt target.txt
# Backup mode: create backup before overwriting
mv -b source.txt target.txt
# Creates target.txt~ backup file
Add this to your .bashrc:
alias mv='mv -i'
4. Update Mode#
Only move when the source is newer than the target:
mv -u newer.log /var/log/
Great for log synchronization — avoids overwriting fresher data.
Edge Cases#
Target: Directory vs File#
mkdir backup
mv file.txt backup/ # file.txt moves into backup directory
# But if backup is a file...
mv file.txt backup # backup file gets overwritten!
Add a trailing / to clarify your intent:
mv file.txt backup/ # Clearly expects backup to be a directory; errors if not
Target Already Exists as Directory#
mkdir target
mv src/ target/
# Result: target/src/, NOT replacing target/
mv places the source directory inside the target. To replace, you need rm -rf target/; mv src/ target/.
Permission Nuances#
mv requires write permission on the source directory (to remove the old dentry) and target directory (to create the new dentry), but NOT on the file itself:
# You can mv a read-only file
chmod 444 readonly.txt
mv readonly.txt new_name.txt # Succeeds!
Many people think a read-only file can’t be moved. But moving modifies the directory, not the file.
Under the Hood: The rename() Syscall#
Linux’s rename() syscall is atomic — it either succeeds completely or fails completely, no intermediate state:
#include <stdio.h>
#include <errno.h>
int main() {
if (rename("old.txt", "new.txt") != 0) {
perror("rename failed");
// EXDEV: cross-device, need manual copy + unlink
if (errno == EXDEV) {
printf("Cross-device link, need manual copy\n");
}
return 1;
}
printf("Renamed successfully\n");
return 0;
}
The EXDEV error code (errno 18) signals a cross-filesystem operation. The mv command detects this and automatically switches to copy + unlink mode.
Atomicity has a practical benefit: in concurrent scenarios, using mv to replace config files is safe:
# Atomic config file update
mv config.json.tmp config.json
# Other processes read either the old or new file, never a partial one
This is the foundation of many hot-reload configurations.
Summary#
- Within the same filesystem,
mvmodifies dentries — instant - Across filesystems,
mvis effectivelycp + rm mvchecks directory permissions, not file permissionsrename()is atomic — perfect for concurrent-safe file replacement- Always use
mv -ito prevent accidental overwrites
Want to try mv variations online? Check out the Linux mv Command Guide.
Related tools: Linux cp File Copy | Linux ls Directory Listing