mv 命令详解
更新时间:2026-08-29。本文是「一个命令一个文档」系列,属于文件与目录操作命令族。
mv既能"搬"又能"改名",是日常整理文件的主力。
为什么写 mv?因为它有个反直觉的点:同一个磁盘分区里 mv 几乎瞬时完成,哪怕文件几个 G——因为它根本没动数据,只是改了目录里的记录。理解这点,你就不会在"移动大文件"时干等进度条了。
mv(move,移动)把文件或目录从源路径挪到目标路径。当源和目标在同一文件系统,它只是重命名目录项;跨文件系统才真正复制+删除。
一、最基本的用法
mv old.txt new.txt # 重命名(同目录内)
mv file.txt ~/docs/ # 移动到其他目录,文件名不变
mv a.txt b.txt dir/ # 多个源 + 最后必须是目录
mv dir1/ dir2/ # 移动整个目录重命名和移动在
mv眼里是同一件事:都是"把某个路径名改成另一个"。mv a b在当前目录就是重命名。
二、高频选项一张表
| 选项 | 作用 | 示例 |
|---|---|---|
-i | 覆盖前交互确认 | mv -i a b |
-n | 不覆盖已存在目标(no-clobber) | mv -n *.log /backup |
-u | 仅当源更新时才移动(update) | mv -u src/* dst/ |
-b | 覆盖前先备份目标 | mv -b a b |
-v | 显示正在移动什么(verbose) | mv -v *.txt ~/docs |
-f | 强制,忽略确认/只读(force) | mv -f a b |
--backup | 精细备份控制(numbered 等) | mv --backup=numbered a b |
-i和-n冲突时-n优先(不覆盖)。生产环境建议alias mv='mv -i'写进.bashrc,避免手滑覆盖。
三、实战 demo
demo 1:批量重命名(把 .txt 改成 .md)
# 错误写法 mv *.txt *.md 不行(目标不能是个模式)
# 正确:用循环
for f in *.txt; do mv "$f" "${f%.txt}.md"; done
# ${f%.txt} 去掉尾部 .txt,再补 .md批量改名是 mv 的高频需求,记住"循环 + 参数展开"这个范式。
demo 2:整理下载目录,按扩展名归档
mkdir -p ~/sorted/images ~/sorted/docs
mv -v *.jpg *.png ~/sorted/images/
mv -v *.pdf *.docx ~/sorted/docs/通配符一次搬一类文件,配合 -v 看清搬了什么。
demo 3:安全地移动,防止覆盖已有文件
mv -n *.log /backup/logs/ # 已存在的绝不覆盖
# 或要留原版备份:
mv -b app.conf app.conf.old # 若 app.conf.old 存在会被改名成 .old~demo 4:跨磁盘迁移大文件(理解"真拷贝")
time mv big.iso /mnt/external/ # 跨 U 盘/外置盘时,mv 实际是 cp+rm
# 同盘内 mv 是瞬间(仅改目录项);跨盘会慢,因为要复制数据想保留属性并增量,大目录迁移直接上 rsync:rsync -a --remove-source-files src/ dst/。
demo 5:移动时显示进度(大目录心里有底)
mv -v project/ /srv/project/ # -v 逐个打印移动了哪些四、同盘移动 vs 跨盘移动的真相
这是 mv 最值得理解的内部机制:
- 同文件系统:
mv调用rename()系统调用,只改目录项(把"父目录A里有file"改成"父目录B里有file"),数据块一个字节没动。所以 GB 级文件也瞬间完成。 - 跨文件系统:rename 失败(不能跨盘改名),
mv退回"复制数据到新位置 + 删除旧的"。这时慢,且中途失败可能留半截。
df -h . /mnt/external # 看源和目标是否同一文件系统(同一行设备=同盘)所以从
/home移到/data(若不在同一分区),mv其实就是在做拷贝。需要断点续传或远程,用 rsync。
五、和 cp / rm 的关系
- 想复制而非移动 → cp。
- 移动后想撤销?
mv没有 undo。养成-i习惯,或先cp -b留备份。 - 移动 = "先 cp 再 rm 源",所以移动失败可能留下源文件(好消息:不会丢),但也可能目标已建、源还在,需手动清理。
六、常见坑
mv a b若 b 是已存在目录,a 会移进 b 里面(变成 b/a);若 b 是已存在文件,a 会覆盖 b。行为随目标类型变,容易误判,加-i保险。- 移动正在被程序写的文件(如日志),可能导致程序写错位置;先停进程再移。
.和..不能 mv;mv dir .会报"cannot move"。- 通配符
mv * /tmp在极多文件时报"参数过长",用find . -maxdepth 1 -exec mv {} /tmp \;。
七、进阶:批量改名与整理的实战套路
mv 在"移动"之外,最常用的身份是批量改名和把散落文件归位。这类活 shell 循环比任何图形工具都快:
# 把一堆 .jpeg 统一改成 .jpg(${f%.jpeg} 去掉尾部最短匹配,只动扩展名)
for f in *.jpeg; do mv "$f" "${f%.jpeg}.jpg"; done
# 给文件名批量加日期前缀(备份归档常用)
for f in report*.txt; do mv "$f" "2026-$(basename "$f")"; done
# 按文件修改日期丢进对应子目录,做日志归档
for f in *.log; do d=$(date -r "$f" +%Y-%m-%d); mkdir -p "$d"; mv "$f" "$d/"; done两个必记点:变量一定用双引号包住,否则文件名里的空格会把一条命令拆成多条;${f%.jpeg} 比 sed 改名更省事,只动扩展名不动前缀。需要复杂正则重命名时再上 rename 命令。
八、边界情况的延伸
mv不能"原地替换正在运行的程序文件":它改的是目录项,正在跑的进程仍用旧 inode。想热更新运行中的程序,得 cp 覆盖新文件 + 重启进程,或用install这类原子替换。- 目标类型决定行为:
mv a b中 b 若是已存在目录,a 会移进 b 内(变成 b/a);b 若是已存在文件,a 覆盖 b。加-i避免误判。 - 通配符爆炸:
mv * /tmp文件极多时报"参数过长",改用find . -maxdepth 1 -exec mv {} /tmp \;。 - 移动正在被写的文件:先停进程再移,否则程序可能写到错误位置。
同盘
mv是"改名",跨盘是"拷贝+删除"。重要数据跨盘移动前,先 rsync 兜底。
相关命令
一句话总结
mv = 移动/重命名:同文件系统内只是改目录项(GB 文件也瞬间),跨盘才真拷贝+删源;默认同名静默覆盖,用 -i 确认、-n 不覆盖、-b 先备份;批量改名靠 shell 循环,大目录/远程迁移换 rsync。