mv 是什么
mv 有两个面孔:同一文件系统内它只是修改目录项,底层是一次 rename 调用,瞬间完成、不消耗额外空间,而且是原子操作——目标要么是旧内容要么是新内容,不存在中间态;跨文件系统时它退化为复制加删除,耗时随数据量增长,中途中断会留下不完整的目标与完整的源。默认行为上它不询问就覆盖同名目标,这一点和 cp 一样,却比 cp 更常被忽视,因为「移动」听起来不像「覆盖」。
基本信息
| 适用平台 | Linux 全发行版与 macOS(GNU coreutils / BSD mv;-u、-t、--backup 的具体行为存在版本差异) |
|---|---|
| 命令语法 | mv [选项] 源... 目标 |
| 常用选项 | -i 覆盖前询问、-n 不覆盖已存在文件、-f 强制覆盖不询问、-v 显示过程、-u 仅当源更新时移动、-b 覆盖前生成备份、-S 指定备份后缀、-T 把目标当普通文件而非目录 |
| 权限要求 | 需要对源目录与目标目录都有写权限;跨文件系统移动还要求目标空间足够 |
| 元数据 | 移动不改变文件属主与权限;目录的 mtime 会因内容变化而更新 |
典型使用场景
- 重命名:同目录内改变名字,即时完成且不改动 inode
- 归档搬迁:把过期数据整体移到备份目录,路径变化而数据不动
- 原子发布:先写临时文件,完成后 mv 覆盖正式文件,读取方看到的始终是完整版本
- 回收站模式:删除前先 mv 到 trash 目录,观察一段时间再真正清理
- 目录改名前的保护:改名前确认目标名不存在,避免把目录移进另一个同名目录里
- 跨盘搬运:了解它实际是复制加删除,据此决定是否改用 rsync 以便断点续传与校验
常用示例
常用示例
mv old-name.txt new-name.txt
mv report-2026-*.pdf /data/reports/
mv -i data.csv /backup/ # 覆盖前询问
mv -n a.txt b.txt # 不覆盖已存在文件
mv -v /data/old /data/archive/2026-10 # 显示移动过程
mv -T tmp.conf /etc/app/app.conf # 目标按普通文件处理,避免误入目录
mv -b app.conf app.conf.bak # 覆盖前保留备份(GNU)选项对照
| 选项 | 作用 | 使用建议 |
|---|---|---|
| -i | 目标存在时询问 | 手工操作时的默认习惯,避免误覆盖 |
| -n | 目标存在时直接跳过 | 脚本里比 -i 更合适,不会阻塞等待输入 |
| -f | 不询问直接覆盖 | 仅在明确知道要覆盖时使用 |
| -u | 仅当源比目标新时才移动 | GNU 扩展,增量搬迁时方便,跨平台脚本要确认支持情况 |
| -T | 把目标视为普通文件,不当作目录 | 脚本里目标路径可能不存在时更可控 |
| -b | 覆盖前把目标改名备份 | 多一层后悔药,注意会累积备份文件 |
目标已存在时的行为取决于目标的类型:目标是目录,源会被移入该目录;目标是文件,源会覆盖它。要在同一目录里改名而目标名恰好存在,就会变成覆盖——这正是 mv 误操作的主要来源。
同文件系统内的 mv 是原子的,这是配置文件发布与日志切换的经典手法:先把内容写到临时文件,校验无误后用 mv 一次覆盖,读取方不会读到写了一半的文件。跨文件系统时这个保证不成立,需要额外机制保证一致性。
跨文件系统移动大目录既慢又脆弱:中断会留下不完整的目标与完整的源,重跑时可能因目标已存在而报错。重要数据先 rsync 或 cp -a 复制并校验,确认无误后再删除源数据。