跳转到内容

mv

mv(move)用于移动文件和目录,也用于重命名 —— 在 Linux 里这两件事是同一个操作。

Terminal window
mv [选项] 源 目标
mv [选项] 源... 目标目录

目标不存在则是重命名,目标是已存在的目录则是移动进去 给多个源时,最后一个参数必须是已存在的目录 移动目录不需要 -r,这一点和 cp 不同

同一个文件系统内,mv 只是改目录项(调 rename),inode 和数据块原地不动,所以移动一个 100 GB 的文件也是瞬间完成的。

跨文件系统时没有这条捷径,mv 退化成「复制到新位置 + 删除源文件」:

  • 耗时与文件大小成正比
  • 中途断电或 Ctrl-C,目标位置会留下一个不完整的文件
  • inode 号会变,指向源文件的硬链接不会跟过去
Terminal window
df /home /mnt/usb # 两条路径不在同一个文件系统上,就是跨盘搬运
选项 说明
-i 覆盖前提示(interactive)
-n 目标已存在就跳过,不提示(no-clobber)
-f 直接覆盖,不提示(force),默认行为
-u 只在源比目标新、或目标不存在时才移动(update)
-v 打印每一次移动(verbose)
-b 覆盖前先备份,被覆盖的文件加 ~ 后缀(backup)
-t <目录> 显式指定目标目录,目录写在前面(target)
-T 把目标当作普通文件处理,不当成「移进这个目录」

1. 重命名

Terminal window
mv old.txt new.txt
mv olddir newdir

2. 移动到目录

Terminal window
mv a.txt b.txt /tmp/
mv -t /tmp/ a.txt b.txt # 目标在前

-t 的用处是配合 xargs,因为 xargs 只会往命令末尾追加参数:

Terminal window
find . -name '*.log' -print0 | xargs -0 mv -t /tmp/logs/

3. 目标已存在时的歧义

Terminal window
mv src dst

dst 不存在:把 src 重命名成 dst dst 是已存在的目录:变成 dst/src 只想要前一种语义,加 -T 把歧义关掉:mv -T src dst

4. 文件名以 - 开头

Terminal window
mv -- -weird.txt normal.txt
mv ./-weird.txt normal.txt

- 开头的参数会被当成选项,-- 表示选项到此为止,或者给个 ./ 前缀

5. mv 做不了批量改名

Terminal window
mv *.txt *.md # 不会按预期工作

通配符是 shell 展开的,mv 收到的是一串文件名,没有「模式替换」这回事 批量改名用 rename,或者 for 循环配 ${var%.txt} 这类参数展开