在 Linux 中移动文件看起来可能相对简单,但可用的选项比大多数人意识到的要多。本文教导初学者如何在 GUI 和命令行中移动文件,同时也解释了底层实际发生的情况,并探讨了许多经验丰富的用户很少探索的命令行选项。
移动什么?
在深入研究移动文件之前,值得仔细研究一下移动文件系统对象时实际发生的情况。当创建文件时,它会被分配到一个 inode,inode 是文件系统中用于数据存储的固定点。您可以使用 ls
命令查找哪个 inode 映射到文件
$ ls --inode example.txt
7344977 example.txt
当您移动文件时,您实际上并没有将数据从一个 inode 移动到另一个 inode,您只是为文件对象分配了一个新名称或文件路径。事实上,文件在移动后会保留其权限,因为移动文件不会更改或重新创建它。
文件和目录 inode 永远不会暗示继承,而是由文件系统本身决定的。Inode 分配是基于文件创建时间的顺序进行的,并且完全独立于您组织计算机的方式。 “位于”目录内的文件可能具有比其父目录更低的 inode 号,也可能具有更高的 inode 号。例如
$ mkdir foo
$ mv example.txt foo
$ ls --inode
7476865 foo
$ ls --inode foo
7344977 example.txt
但是,当将文件从一个硬盘驱动器移动到另一个硬盘驱动器时,inode 很可能会更改。发生这种情况是因为新数据必须写入新的文件系统。因此,在 Linux 中,移动和重命名文件的操作实际上是相同的操作。无论您是将文件移动到另一个目录还是移动到具有新名称的同一目录,这两个操作都由相同的底层程序执行。
本文重点介绍将文件从一个目录移动到另一个目录。
使用鼠标移动
GUI 是一个友好的,并且对大多数人来说是熟悉的抽象层,它位于复杂的二进制数据集合之上。它也是在 Linux 上移动文件的第一种也是最直观的方式。如果您习惯了桌面体验(从广义上讲),那么您可能已经知道如何在硬盘驱动器上移动文件。例如,在 GNOME 桌面中,从一个窗口拖放到另一个窗口时,默认操作是移动文件而不是复制文件,因此它可能是桌面上最直观的操作之一

KDE Plasma 桌面中的 Dolphin 文件管理器默认提示用户执行操作。在拖动文件时按住 Shift 键会强制执行移动操作

在命令行中移动
在 Linux、BSD、Illumos、Solaris 和 MacOS 上移动文件的 shell 命令是 mv。一个简单的命令,具有可预测的语法,mv <源> <目标> 将源文件移动到指定的目标,每个目标都由绝对或相对文件路径定义。如前所述,mv 是 POSIX 用户常用的命令,以至于它的许多附加修饰符通常是未知的,因此本文将一些有用的修饰符引起您的注意,无论您是新手还是经验丰富的用户。
并非所有的 mv 命令都是由同一批人编写的,因此您可能拥有 GNU mv、BSD mv 或 Sun mv,具体取决于您的操作系统。命令选项因实现而异(BSD mv 根本没有长选项),因此请参考您的 mv 手册页以查看支持哪些选项,或者安装您首选的版本(这就是开源的优势)。
移动文件
要使用 mv 将文件从一个文件夹移动到另一个文件夹,请记住语法 mv <源> <目标>。例如,要将文件 example.txt 移动到您的 Documents 目录
$ touch example.txt
$ mv example.txt ~/Documents
$ ls ~/Documents
example.txt
就像您通过将文件拖放到文件夹图标来移动文件一样,此命令不会用 example.txt 替换 Documents。相反,mv 检测到 Documents 是一个文件夹,并将 example.txt 文件放入其中。
您也可以方便地在移动文件时重命名文件
$ touch example.txt
$ mv example.txt ~/Documents/foo.txt
$ ls ~/Documents
foo.txt
这很重要,因为它使您即使在不想将文件移动到另一个位置时也可以重命名文件,就像这样
$ touch example.txt
$ mv example.txt foo2.txt
$ ls
foo2.txt
移动目录
mv 命令不像 cp 命令那样区分文件和目录。您可以使用相同的语法移动目录或文件
$ touch file.txt
$ mkdir foo_directory
$ mv file.txt foo_directory
$ mv foo_directory ~/Documents
安全地移动文件
如果您将文件复制到已存在同名文件的目录中,则默认情况下,mv 命令会将目标文件替换为您正在移动的文件。此行为称为覆盖,有时这正是您想要的。有时则不是。
某些发行版别名(或者您可以编写您自己的)mv 为 mv --interactive,这将提示您进行确认。有些则不这样做。无论哪种方式,您都可以使用 --interactive 或 -i 选项来确保在两个同名文件发生冲突时 mv 请求确认
$ mv --interactive example.txt ~/Documents
mv: overwrite '~/Documents/example.txt'?
如果您不想手动干预,请改用 --no-clobber 或 -n。此标志会在发生冲突时静默拒绝移动操作。在此示例中,名为 example.txt 的文件已存在于 ~/Documents 中,因此它不会按照指示从当前目录移动
$ mv --no-clobber example.txt ~/Documents
$ ls
example.txt
使用备份移动
如果您使用的是 GNU mv,则备份选项提供了另一种安全移动方式。要创建任何冲突目标文件的备份,请使用 -b 选项
$ mv -b example.txt ~/Documents
$ ls ~/Documents
example.txt example.txt~
此标志确保 mv 完成移动操作,但也保护目标位置中的任何预先存在的文件。
另一个 GNU 备份选项是 --backup,它接受一个参数,用于定义备份文件的命名方式
- existing:如果目标中已存在编号的备份,则会创建编号的备份。否则,将使用 simple 方案。
- none:即使设置了 --backup,也不会创建备份。此选项对于覆盖设置备份选项的 mv 别名很有用。
- numbered:在目标文件后附加一个数字。
- simple:在目标文件后附加一个 ~,可以使用 ls 的 --ignore-backups 选项方便地将其从您的日常视图中隐藏起来。
例如
$ mv --backup=numbered example.txt ~/Documents
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:23 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
可以使用环境变量 VERSION_CONTROL 设置默认备份方案。您可以在 ~/.bashrc 文件中或在命令之前动态设置环境变量
$ VERSION_CONTROL=numbered mv --backup example.txt ~/Documents
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:23 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
-rw-rw-r--. 1 seth users 128 Aug 1 17:22 example.txt.~2~
--backup 选项仍然尊重 --interactive 或 -i 选项,因此即使它在执行覆盖之前创建了备份,它仍然会提示您覆盖目标文件
$ mv --backup=numbered example.txt ~/Documents
mv: overwrite '~/Documents/example.txt'? y
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:24 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
-rw-rw-r--. 1 seth users 128 Aug 1 17:22 example.txt.~2~
-rw-rw-r--. 1 seth users 128 Aug 1 17:23 example.txt.~3~
您可以使用 --force 或 -f 选项覆盖 -i。
$ mv --backup=numbered --force example.txt ~/Documents
$ ls ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:26 example.txt
-rw-rw-r--. 1 seth users 128 Aug 1 17:20 example.txt.~1~
-rw-rw-r--. 1 seth users 128 Aug 1 17:22 example.txt.~2~
-rw-rw-r--. 1 seth users 128 Aug 1 17:24 example.txt.~3~
-rw-rw-r--. 1 seth users 128 Aug 1 17:25 example.txt.~4~
--backup 选项在 BSD mv 中不可用。
一次移动多个文件
当移动多个文件时,mv 将最后一个命名的目录视为目标
$ mv foo bar baz ~/Documents
$ ls ~/Documents
foo bar baz
如果最后一个项目不是目录,则 mv 返回错误
$ mv foo bar baz
mv: target 'baz' is not a directory
GNU mv 的语法相当灵活。如果您无法将目标作为最后一个参数提供给 mv 命令,请使用 --target-directory 或 -t 选项
$ mv --target-directory=~/Documents foo bar baz
$ ls ~/Documents
foo bar baz
当从其他一些命令(例如 find 命令、xargs 或 GNU Parallel)的输出构造 mv 命令时,这尤其有用。
基于 mtime 移动
使用 GNU mv,您可以根据要移动的文件是否比它将替换的目标文件更新来定义移动操作。此选项可以通过 --update 或 -u 选项实现,并且在 BSD mv 中不可用
$ ls -l ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:32 example.txt
$ ls -l
-rw-rw-r--. 1 seth users 128 Aug 1 17:42 example.txt
$ mv --update example.txt ~/Documents
$ ls -l ~/Documents
-rw-rw-r--. 1 seth users 128 Aug 1 17:42 example.txt
$ ls -l
此结果完全基于文件的修改时间,而不是两个文件的差异,因此请谨慎使用。使用简单的 touch 命令很容易欺骗 mv
$ cat example.txt
one
$ cat ~/Documents/example.txt
one
two
$ touch example.txt
$ mv --update example.txt ~/Documents
$ cat ~/Documents/example.txt
one
显然,这不是最智能的更新功能,但它提供了基本的保护,防止覆盖最近的数据。
移动
除了 mv 命令之外,还有更多移动数据的方法,但作为此工作的默认程序,mv 是一个很好的通用选择。现在您了解了可用的选项,您可以比以往更智能地使用 mv。
1 条评论