Moving and Renaming (mv)

The mv command is how you move files and directories from one location to another on Linux — and, because Linux has no separate “rename” command, it is also how you rename things. Under the hood, moving a file within the same filesystem and renaming a file are literally the same operation: both just change where a filename points. Understanding that fact is the key to understanding mv, its speed, and its few sharp edges.

Overview / How it works

Every file on a Linux filesystem is really two things: the file’s actual data (stored in a structure called an inode, which holds the file’s metadata and pointers to its data blocks), and a directory entry — a name that points to an inode number. A directory is essentially a table mapping names to inode numbers.

When you run mv oldname.txt newname.txt and both paths are on the same filesystem, the kernel does not touch the file’s data at all. It performs a single rename() system call: it removes the directory entry oldname.txt, and adds (or replaces) a directory entry newname.txt that points at the exact same inode. This is why renaming or moving a 50 GB file within the same partition is instantaneous — no bytes are copied, only a table entry changes. It’s also why the operation is atomic: at no point does the file briefly “not exist,” so other processes never observe a half-moved state.

When the source and destination are on different filesystems (for example, moving from your root partition / to a mounted USB drive, or across two different mounted volumes), a single rename() is impossible because inode numbers are only meaningful within one filesystem. In that case mv transparently falls back to copying the file’s data to the new location and then deleting the original. This is slower and, unlike a same-filesystem move, not instantaneous or atomic — if the process is interrupted partway, you can end up with a partial copy at the destination and the original still present (or vice versa).

mv also has a dual personality depending on its destination argument. If the destination does not exist, mv treats it as the new name for the source (a rename). If the destination is an existing directory, mv moves the source into that directory, keeping its original filename unless you explicitly type a new one. This dual behavior is the single most common source of confusion for beginners, so pay close attention to it in the examples below.

Syntax

mv [OPTIONS] SOURCE DESTINATION
mv [OPTIONS] SOURCE... DIRECTORY

The first form moves or renames a single item. The second form moves one or more items into an existing directory. Common options:

Flag Meaning
-i Interactive — prompt before overwriting an existing destination file.
-n No-clobber — never overwrite an existing destination file (silently skips it).
-v Verbose — print each source/destination pair as it’s moved.
-b Backup — before overwriting a destination, rename the existing file with a ~ suffix.
-u Update — only move when the source is newer than an existing destination, or the destination is missing.
-f Force — overwrite without prompting, even if permissions would normally ask (overrides an earlier -i).
-T Treat destination as a normal file, not a directory (useful for renaming a directory when a directory of the target name already exists).
-- End of options — treat everything after this as a filename (useful if a filename starts with -).

Examples

Example 1: Renaming a file

mv notes.txt project_notes.txt

Output:

(no output on success)

Since project_notes.txt did not already exist, mv simply renamed notes.txt in place. mv is silent on success by default, following the Unix convention that no news is good news.

Example 2: Moving a file into a directory

mv ~/Downloads/invoice_march.pdf ~/Documents/invoices/

Output:

(no output on success)

Because ~/Documents/invoices/ already exists as a directory, mv moved the file into it, keeping the name invoice_march.pdf. If that trailing directory did not exist, mv would instead try to create a file literally named invoices containing the PDF’s contents — which is almost never what you want.

Example 3: Moving multiple files at once, verbosely

mv -v /var/log/app/*.log /var/log/app/archive/

Output:

renamed '/var/log/app/access.log' -> '/var/log/app/archive/access.log'
renamed '/var/log/app/error.log' -> '/var/log/app/archive/error.log'

The shell expands the glob *.log into a list of matching files before mv even runs, so this is equivalent to listing each log file individually. Because the final argument is a directory, every matched file is moved into it. The -v flag prints each move as confirmation, which is invaluable when scripting.

Example 4: Renaming a file while moving it, safely

mv -i ~/scripts/backup.sh ~/scripts/archived/backup_2026.sh

Output:

mv: overwrite '/home/user/scripts/archived/backup_2026.sh'? 

Here the destination is a full new filename inside an existing directory, so mv both relocates and renames the file in one step. Because a file with that exact destination name already existed, -i made mv pause and ask for confirmation instead of silently overwriting it — typing y proceeds, anything else cancels.

How it works step by step

    Walking through mv report.txt ~/archive/report.txt when both paths are on the same disk partition:

    • The shell resolves both paths (expanding ~ to your home directory) and passes them to the mv binary as two arguments.
    • mv checks whether the destination exists and whether it is a directory or a plain file, which determines whether this is a rename or a move-into.
    • If a destination file already exists and no safety flag like -i/-n was given, mv will overwrite it without asking — this is the default and it is destructive.
    • mv calls the rename() system call with the old and new paths. The kernel updates the directory entry atomically: the inode number that used to answer to report.txt now answers to ~/archive/report.txt.
    • No file data is read or written, so the operation completes in constant time regardless of file size, as long as source and destination share a filesystem.

    If the destination is on a different filesystem, step 4 instead becomes: read the source file’s data and write a full copy at the destination, then delete the original source file — effectively a manual cp followed by rm, performed for you.

    Common Mistakes

    Mistake 1: Overwriting a file by accident

    # Wrong: silently destroys the existing config.yaml
    mv config_new.yaml config.yaml

    By default mv never asks before overwriting an existing destination file — the old config.yaml is gone the instant this runs, with no trash bin to recover it from. Always use -i (or -n if you’d rather skip than prompt) when the destination might already exist:

    mv -i config_new.yaml config.yaml

    Mistake 2: Trailing slash typo turning a move into an accidental rename

    # Wrong: if 'backups' does not exist, this creates a FILE named 'backups'
    # containing the contents of report.csv, instead of moving it into a folder
    mv report.csv ~/backups

    If ~/backups doesn’t exist as a directory, mv treats it as a target filename and renames report.csv to a file called backups. Always confirm the directory exists first (or create it), and consider using a trailing slash as a sanity signal to yourself:

    mkdir -p ~/backups
    mv report.csv ~/backups/

    Mistake 3: Unquoted variables with spaces or globs

    # Wrong: word-splits on spaces in the filename, mv sees multiple arguments
    file="Q1 Report.docx"
    mv $file ~/Documents/

    Without quotes, Bash splits $file on whitespace before mv ever sees it, so mv receives Q1 and Report.docx as two separate arguments instead of one filename — this usually fails with “No such file or directory” or moves the wrong thing. Always quote variable expansions:

    file="Q1 Report.docx"
    mv "$file" ~/Documents/

    Best Practices

    • Default to mv -i in interactive use (or alias mv to mv -i in your shell config) so you get a warning before any overwrite.
    • In scripts, prefer -n (no-clobber) over -i so the script doesn’t hang waiting for input it will never receive.
    • Always quote path and variable arguments — mv "$src" "$dest" — to survive spaces and special characters safely.
    • When moving into a directory, add the trailing slash (dest/) so a typo in the directory name fails loudly instead of silently creating a same-named file.
    • Use -v in scripts that move important files, so logs show exactly what happened.
    • For anything irreversible or high-stakes, consider cp then verify then rm, rather than a one-shot mv, if you want an extra safety window.
    • Remember mv across filesystems is a copy-then-delete: for very large files, a stray power loss mid-move can leave things in a partial state — for critical cross-filesystem transfers, verify checksums afterward.

    Practice Exercises

    • Create a file called draft.txt, then rename it to final.txt using a single mv command. Confirm with ls that draft.txt no longer exists.
    • Create a directory ~/practice/incoming and three files named a.log, b.log, c.log in your home directory. Move all three into incoming in one command, using -v so you can see each move confirmed.
    • Create two files with the same name in different directories (e.g. ~/practice/notes.txt and ~/practice/incoming/notes.txt). Try moving the first on top of the second using mv -i and observe the prompt; answer n to cancel, then try again with -n and confirm the file is left untouched.

    Summary

    • mv both moves and renames files/directories — Linux has no separate rename command.
    • On the same filesystem, mv is a single atomic rename() system call that just updates a directory entry — no data is copied, so it’s instant regardless of file size.
    • Across filesystems, mv falls back to copy-then-delete, which is slower and not atomic.
    • If the destination is an existing directory, the source is moved into it; if not, the destination becomes the new name — this distinction causes most beginner mistakes.
    • mv overwrites existing destination files silently by default — use -i or -n to protect yourself.
    • Always quote variables and paths ("$file") to avoid word-splitting on spaces.