Skip to content

mv

mvmove)是 Linux 中唯一一个让你"瞬间移动"任意大小文件的命令——同文件系统内它不复制数据,只改一个指针。这层原子性让它成为安全部署、事务性文件更新和批量重命名的基建工具。

速查卡片

需求命令
重命名文件mv old.txt new.txt
移动文件到目录mv file.txt /target/dir/
移动多个文件到目录mv a.txt b.txt /target/dir/
覆盖前确认mv -i src dst
强制覆盖不提示mv -f src dst
不覆盖已存在文件mv -n src dst
仅源更新时才移动mv -u src dst
覆盖前备份旧文件mv -b src dst(旧文件 → dst~)
详细输出mv -v src dst
交换两个文件mv --exchange a.txt b.txt
拒绝跨文件系统(保原子性)mv --no-copy /tmp/f /mnt/usb/f
安全部署(原子替换)make > output.new && mv output.new output

概述

mv 兼具重命名移动两种功能。它的实现取决于源和目标是否在同一文件系统:

  • 同文件系统:调用 rename(2) 系统调用——只修改目录项指针,不复制数据,inode 不变,整个操作是原子的
  • 跨文件系统:回退为 cp + unlink——完整复制数据后删除源

这种双重行为是理解 mv 一切特性的起点。选项方面,mv 继承了 cp 的覆盖控制家族(-i/-f/-n/-u/-b),并独有 --exchange(交换)和 --no-copy(拒绝跨设备)两个选项。

命令签名

bash
# 形式一:重命名/移动单个文件
mv [OPTION]... [-T] SOURCE DEST

# 形式二:多文件移动到目录
mv [OPTION]... SOURCE... DIRECTORY

# 形式三:-t 目标在前(GNU 扩展)
mv [OPTION]... -t DIRECTORY SOURCE...
  • -T:强制将 DEST 视为普通文件(即使它是已存在的目录也不把源移进去)

基础用法

示例一:最简——重命名

bash
$ mv oldname.txt newname.txt
$ mv file.txt /target/dir/                # 移动到目录,保留原名
$ mv file.txt /target/dir/newname.txt     # 移动并改名

示例二:批量移动

bash
$ mv *.log /archive/logs/                 # 所有 .log 文件移入 /archive/logs/
$ mv dir1 dir2 dir3 /target/              # 多个目录一起移动

示例三:覆盖控制

bash
$ mv -i src.txt dst.txt                   # 覆盖前确认
mv: overwrite 'dst.txt'? y

$ mv -n src.txt dst.txt                   # 不覆盖,静默跳过

$ mv -u src.txt dst.txt                   # 仅 src 更新时才覆盖

$ mv -b src.txt dst.txt                   # 覆盖前备份
# dst.txt 旧内容 → dst.txt~

-i/-f/-n 同时指定时,最后一个生效:

bash
$ mv -f -i src.txt dst.txt   # -i 胜出 → 提示确认
$ mv -i -n src.txt dst.txt   # -n 胜出 → 静默跳过

示例四:原子文件更新——mv 最有价值的用法

bash
# ❌ 非原子:写入过程中文件可能不完整
echo "new config" > /etc/app.conf

# ✅ 原子:先写入临时文件,再原子替换
echo "new config" > /etc/app.conf.new
mv /etc/app.conf.new /etc/app.conf

mv 发生的瞬间,/etc/app.conf 从旧内容"跳变"到新内容——不存在观察者看到文件为空的窗口。这是守护进程热重载、配置文件部署的标准模式。

核心原理:rename(2) 原子操作

mvcp 的本质区别在于底层系统调用:

                   ┌─ 同文件系统 ──→ rename(2) 原子操作
mv SOURCE DEST ────┤
                   └─ 跨文件系统 ──→ cp + unlink(非原子)

同文件系统内(rename(2)

特性行为
数据复制——只修改源和目标所在目录的目录项
inode完全不变
硬链接所有指向该 inode 的硬链接仍有效
已打开的文件持有文件描述符的进程不受影响(通过 inode 访问)
速度瞬间完成,与文件大小无关
原子性不可能出现中间状态——要么旧路径存在,要么新路径存在
特性行为
数据复制需要完整读取源、写入目标
inode变化(新文件系统上的新 inode)
硬链接旧硬链接仍指向原 inode,但那是源位置的数据
速度等于 cp + rm 的时间
原子性非原子——中断后目标有不完整文件,源仍存在

--no-copy —— 强制原子性

bash
$ mv --no-copy /tmp/file.txt /mnt/usb/
mv: cannot move '/tmp/file.txt' to '/mnt/usb/file.txt': cross-device move not permitted

在需要保证原子性的脚本中,--no-copy 让跨文件系统的 mv 直接失败,而不是静默回退为复制。

--exchange —— mv 独有的交换操作

bash
$ mv --exchange a.txt b.txt
# a.txt ↔ b.txt 原子互换,没有中间状态

这是唯一一个能原子交换两个文件路径的命令。典型场景:

bash
# 原子切换符号链接(蓝绿部署)
ln -s /srv/app-v2 /srv/app-new
mv --exchange /srv/app /srv/app-new    # /srv/app → v1, /srv/app-new → v2
# 实际上就是交换了符号链接的目标,然后删掉旧版

# 批量重命名中配合使用

目录操作的特殊规则

不能把目录移入自身

bash
$ mv work/ work/sub/
mv: cannot move 'work/' to a subdirectory of itself, 'work/sub/work'

不能合并目录

bash
$ mv src_dir/ dst_dir/
# 如果 dst_dir 已存在且非空且与 src_dir 不同名 → 报错:
mv: cannot overwrite directory 'dst_dir' with non-directory
# 或:
mv: cannot move 'src_dir' to 'dst_dir/src_dir': Directory not empty

mv 不会递归合并目录内容。需要合并时用 cp -r + rm -rrsync --remove-source-files

同文件系统 vs 跨文件系统移动目录

同文件系统跨文件系统
实现修改父目录的目录项递归 cp + 递归 rm
速度瞬间(与目录内文件多少无关)与目录总大小成正比
inode目录本身的 inode 不变变化

符号链接行为

mv 操作符号链接本身,从不跟随:

bash
$ ln -s /etc/hostname link
$ mv link /tmp/
$ ls -l /tmp/link
lrwxrwxrwx ... /tmp/link -> /etc/hostname    # 链接被移动,目标不变
  • 如果目标是符号链接指向目录 → mv 报错(歧义),需 -T 强制
  • 源和目标都是指向同一文件的符号链接 → 允许(POSIX 规定)

选项互斥规则

bash
mv -i -n src dst    # -n 胜出:静默跳过
mv -n -i src dst    # -i 胜出:提示确认
mv -f -n src dst    # -n 胜出:静默跳过
mv -f -i src dst    # -i 胜出:提示确认(POSIX 和 GNU 都是后者胜出)

常用命令组合

bash
# 批量重命名——仅当目标不存在
for f in *.jpeg; do mv -n "$f" "${f%.jpeg}.jpg"; done

# 配合 find 批量移动
find . -name '*.log' -mtime +30 -exec mv -t /archive/logs/ {} +

# 备份式移动
mv -bv /tmp/staging/* /srv/app/

# 原子部署
go build -o server.new && mv server.new server && systemctl restart myserver

# 蓝绿原子切换
ln -sfn /srv/app-green /srv/app-live
# (mv --exchange 是另一种方式)

脚本安全模式

bash
# ✅ 原子更新
generate_config > /etc/app.conf.new
mv /etc/app.conf.new /etc/app.conf

# ✅ 仅源更新时才移动(避免不必要的时间戳变更)
mv -u /tmp/cache/* /var/cache/

# ✅ 不覆盖已有
mv -n /tmp/staging/* /srv/deploy/

# ✅ 覆盖前备份
mv -b config.new /etc/app/config

# ✅ 强制原子,失败即退出
mv --no-copy /tmp/staging/output /srv/prod/output || {
    echo "跨设备,无法原子移动" >&2
    exit 1
}

常见报错

错误信息原因解决
mv: cannot move 'x' to a subdirectory of itself尝试把目录移入自己的子目录检查路径,确认目标不在源内
mv: cannot overwrite directory with non-directory目标是非目录,源是目录删除目标文件或选不同目标路径
mv: cannot overwrite non-directory with directory目标是目录,源是非目录删除目标目录或选不同目标路径
mv: Directory not empty目标目录已存在且非空rm -r 目标或选不同路径
mv: 'src' and 'dst' are the same file源和目标解析为同一文件检查路径;同文件移动时加后缀
mv: will not overwrite just-created同批次中重名文件重复移动find 结果中有同名字文件,用 rsync
mv: cross-device move not permitted--no-copy 阻止了跨文件系统移动去掉 --no-copy 或用 cp+rm

| mv: Permission denied | 源父目录无写权限(删除旧名需要)或目标目录无写权限 | chmodsudo |

注意事项

  • 目录不能合并——这是 mvcp -r 最大的使用差异
  • 跨文件系统移动大目录耗时很长——等于完整复制后再删除,中断不会丢数据(源还在)
  • mv 操作的是目录项,不是数据——同文件系统内已打开的文件继续有效,通过 /proc/<pid>/fd/<n> 仍可访问
  • 尾部斜杠被自动去掉——与 cp 不同,mvsrc/src 行为一致
  • 源和目标是同一文件时:GNU mv 诊断但退出码 0;POSIX rename() 检测到同 inode 则无事发生

常见误区

❌ 误区✅ 正解
"mv 就是先 cp 再 rm"同文件系统内只改目录项指针——不复制数据,inode 不变,是原子操作
"mv 之后 inode 会变"同文件系统内 inode 完全不变,已打开文件的进程无感知
"mv dir/ dst/mv dir dst 有区别"GNU mv 自动去掉尾部斜杠,行为一致
"可以 mv 合并两个目录"mv 不能合并——要用 cp -r + rm -rrsync
"mv -f 可以覆盖非空目录"-f 只控制覆盖提示,不改变目录合并限制
"跨文件系统 mv 也是原子的"跨设备回退为 cp+rm,非原子

mv vs cp 场景速查

场景mvcp
重命名
同设备移动✅ 瞬间、原子
保留 inode/硬链接
保留源文件
交换两个文件--exchange
合并目录cp -r
复制到远程❌(用 scp/rsync

版本与规范信息

事件说明
POSIX 纳入Issue 2
rename(2) 原子性POSIX.1-2001 明确规定
GNU --exchangecoreutils ≥ 9.0
GNU --no-copycoreutils ≥ 9.0
GNU coreutils 当前9.11(2026-04)

macOS 特别说明

  • macOS 的 mv 来自 BSD,无 --exchange--no-copy-t-T 等 GNU 扩展
  • BSD mv-f/-i/-n 行为与 GNU 一致
  • macOS 文件系统(APFS)同一宗卷内 mv 同样是原子的
  • macOS 无 --strip-trailing-slashes(但 BSD 版本也不依赖尾部斜杠歧义)

来源

来源链接
GNU coreutils mv man pagehttps://man7.org/linux/man-pages/man1/mv.1.html
GNU coreutils 官方文档https://www.gnu.org/software/coreutils/mv
rename(2) 系统调用https://man7.org/linux/man-pages/man2/rename.2.html
POSIX mv 规范https://pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html
Baeldung: mv 指南https://www.baeldung.com/linux/mv
整理时间2026-07-14