在 Linux 中复制文件

了解在 Linux 上复制文件的多种方法,以及每种方法的优势。
128 位读者喜欢这篇文章。
Filing papers and documents

过去,复印文件需要办公室里专门的工作人员,然后需要专门的机器。如今,复印已成为计算机用户不假思索就能完成的任务。在计算机上复制数据非常简单,以至于在您没有意识到的情况下就完成了复制,例如将文件拖动到外部驱动器时。

数字实体易于复制的概念非常普遍,因此大多数现代计算机用户不会考虑复制工作的可用选项。然而,在 Linux 上复制文件有几种不同的方法。每种方法都有细微的特性,根据您需要完成的任务,这些特性可能会对您有所帮助。

以下是在 Linux、BSD 和 Mac 上复制文件的几种方法。

在 GUI 中复制

与大多数操作系统一样,如果您喜欢这种工作方式,您可以在 GUI 中完成所有文件管理。

拖放

最明显的复制文件方式是您可能已经习惯的在计算机上复制文件的方式:拖放。在大多数 Linux 桌面环境中,默认情况下,从一个本地文件夹拖放到另一个本地文件夹会移动文件。您可以在开始拖动文件后按住 Ctrl 键,将此行为更改为复制操作。

您的光标可能会显示一个指示符,例如加号,以表明您处于复制模式

Copying a file.

请注意,如果文件存在于远程系统中,无论是 Web 服务器还是您通过文件共享协议访问的您自己网络中的另一台计算机,默认操作通常是复制,而不是移动文件。

右键单击

如果您发现拖放文件在桌面上不够精确或笨拙,或者这样做会使您的手过多地离开键盘,您通常可以使用右键单击菜单复制文件。这种可能性取决于您使用的文件管理器,但通常,右键单击会生成一个上下文菜单,其中包含常用操作。

上下文菜单复制操作将文件路径(文件在系统上的位置)存储在剪贴板中,以便您可以将文件粘贴到其他位置

Copying a file from the context menu.

在这种情况下,您实际上并没有将文件的内容复制到剪贴板。相反,您复制的是文件路径。当您粘贴时,您的文件管理器会查看剪贴板中的路径,然后运行复制命令,将位于该路径的文件复制到您要粘贴到的路径中。

在命令行中复制

虽然 GUI 是一种通常熟悉的文件复制方式,但在终端中复制可能更有效。

cp

在桌面上复制和粘贴文件的明显终端等效命令是 cp 命令。此命令复制文件和目录,并且相对简单。它使用熟悉的目标(严格按照该顺序)语法,因此要将名为 example.txt 的文件复制到您的 Documents 目录中

$ cp example.txt ~/Documents

就像将文件拖放到文件夹一样,此操作不会用 example.txt 替换 Documents。相反,cp 检测到 Documents 是一个文件夹,并将 example.txt 的副本放入其中。

您还可以在复制文件时方便地(且高效地)重命名文件

$ cp example.txt ~/Documents/example_copy.txt

这个事实很重要,因为它允许您在与原始文件相同的目录中创建文件的副本

$ cp example.txt example.txt
cp: 'example.txt' and 'example.txt' are the same file.
$ cp example.txt example_copy.txt

要复制目录,您必须使用 -r 选项,该选项代表 --recursive。此选项在目录 inode 上运行 cp,然后在目录中的所有文件上运行 cp。如果没有 -r 选项,cp 甚至无法识别目录是可以复制的对象

$ cp notes/ notes-backup
cp: -r not specified; omitting directory 'notes/'
$ cp -r notes/ notes-backup

cat

cat 命令是最容易被误解的命令之一,但这仅仅是因为它体现了 POSIX 系统的极端灵活性。在 cat 所做的所有其他事情(包括其预期的连接文件的用途)中,它也可以复制。例如,使用 cat,您只需一个命令即可从一个文件创建两个副本。您无法使用 cp 执行此操作。

使用 cat 复制文件的意义在于系统解释操作的方式。当您使用 cp 复制文件时,文件的属性会与文件本身一起复制。这意味着重复文件的文件权限与原始文件相同

$ ls -l -G -g
-rw-r--r--. 1 57368 Jul 25 23:57  foo.jpg
$ cp foo.jpg bar.jpg
-rw-r--r--. 1 57368 Jul 29 13:37  bar.jpg
-rw-r--r--. 1 57368 Jul 25 23:57  foo.jpg

但是,使用 cat 将文件内容读取到另一个文件中会调用系统调用来创建新文件。这些新文件受您默认的 umask 设置的约束。要了解有关 umask 的更多信息,请阅读 Alex Juarez 关于 umask 和通用权限的文章。

运行 umask 以获取当前设置

$ umask
0002

此设置意味着在此位置创建的新文件被授予 664 (rw-rw-r--) 权限,因为 umask 设置的第一个数字没有掩码任何内容(并且可执行位不是文件创建的默认位),并且写入权限被最后一位数字阻止。

当您使用 cat 复制时,您实际上并没有复制文件。您使用 cat 读取文件的内容,然后将输出重定向到新文件中

$ cat foo.jpg > baz.jpg
$ ls -l -G -g
-rw-r--r--. 1 57368 Jul 29 13:37  bar.jpg
-rw-rw-r--. 1 57368 Jul 29 13:42  baz.jpg
-rw-r--r--. 1 57368 Jul 25 23:57  foo.jpg

如您所见,cat 创建了一个应用了系统默认 umask 的全新文件。

最后,当您只想复制文件时,技术细节通常并不重要。但有时您想要复制文件并最终获得一组默认权限,而使用 cat,您可以在一个命令中完成所有操作

rsync

rsync 命令是一个用于复制文件的多功能工具,其显著功能是同步源和目标。在最简单的情况下,rsync 可以像 cp 命令一样使用

$ rsync example.txt example_copy.txt
$ ls 
example.txt    example_copy.txt

该命令的真正强大之处在于它能够在不需要时复制。如果您使用 rsync 将文件复制到目录中,但该文件已存在于该目录中,则 rsync 不会费心执行复制操作。在本地,这个事实不一定意味着什么,但如果您要将千兆字节的数据复制到远程服务器,此功能将产生天壤之别。

然而,即使在本地,也确实有意义的是该命令区分共享相同名称但包含不同数据文件的能力。如果您曾经发现自己面临两个本应是相同目录的副本,那么 rsync 可以将它们同步到一个目录中,其中包含来自每个目录的最新更改。这种设置在尚未发现版本控制魔力的行业以及其中有一个真理来源需要传播的备份解决方案中非常常见。

您可以通过创建两个文件夹来有意地模拟这种情况,一个名为 example,另一个名为 example_dupe

$ mkdir example example_dupe

在第一个文件夹中创建一个文件

$ echo "one" > example/foo.txt

使用 rsync 同步这两个目录。此操作最常用的选项是 -a(对于 archive,它确保保留符号链接和其他特殊文件)和 -v(对于 verbose,向您提供有关命令进度的反馈)

$ rsync -av example/ example_dupe/

现在,这两个目录包含相同的信息

$ cat example/foo.txt
one
$ cat example_dupe/foo.txt
one

如果您正在视为源的文件发生偏离,则目标将更新以匹配

$ echo "two" >> example/foo.txt
$ rsync -av example/  example_dupe/
$ cat example_dupe/foo.txt
one
two

请记住,rsync 命令旨在复制数据,而不是充当版本控制系统。例如,如果目标中的文件不知何故领先于源中的文件,则该文件仍将被覆盖,因为 rsync 会比较文件的差异,并假定目标始终旨在镜像源

$ echo "You will never see this note again" > example_dupe/foo.txt
$ rsync -av example/  example_dupe/
$ cat example_dupe/foo.txt
one
two

如果没有更改,则不会发生复制。

rsync 命令具有许多 cp 中不可用的选项,例如设置目标权限、排除文件、删除未出现在两个目录中的过时文件等等。将 rsync 用作 cp 的强大替代品,或者仅用作有用的补充。

多种复制方式

在 POSIX 系统上有很多方法可以实现基本相同的结果,因此开源在灵活性方面的声誉似乎名副其实。我是否遗漏了有用的数据复制方法?在评论中分享您的复制技巧。

标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。他曾在电影和计算机行业工作,通常同时从事这两项工作。

4 条评论

感谢您深入探讨复制的机制,Seth。很容易忘记,复制文件不仅仅是使用图形文件管理器或 cp。或者您可以使用 rsync 将文件从计算机上的一个文件夹复制到另一个文件夹 - 我只用它在计算机之间复制。

当我将我的 /home/gregp 目录备份到外部驱动器时,我首先转到上一级,然后
cp -av gregp /destination
-a 标志代表 archive,与 -dR 相同,一个重要的功能是它保留时间戳。我发现自己有时会根据我创建或上次保存文件的时间来查找文件,因此时间戳可能非常有用。我为什么要转到上一级而不是停留在 /home/gregp 中并执行此操作?
cp -av * /destination
原因是这种方法不会复制点文件和点目录(所谓的隐藏文件)。
与 cp 相关的命令(在某种程度上)是 mv,因为这在某种意义上是 cp 文件,然后删除原始文件。据我所知,它通过更改文件注册表而不是实际复制来完成此操作,因为 mv 保留与原始文件相同的时间戳。

mv 可以在其目录条目中重命名文件,或将名称放在其他目录中,或重命名并将名称放在其他目录中。在任何一种情况下,文件的 inode 编号在移动后都不会更改,因此文件的数据块不会被触及。

但如果目标位于不同的文件系统上,mv 会将数据块复制到新位置,然后从原始目录中删除目录条目(名称:inode 对)。

当文件被移动 (mv) 时,修改时间 (mtime) 保持不变,因为文件数据没有更改(尽管它可能已被复制到不同的文件系统)。

在任何一种情况下,您都应该看到更新的 ctime(更改时间),因为文件元数据(名称)已更改。

回复 作者:Greg P

非常完整的指南。或许提及在 cp 命令中使用通配符(如 *)的功能会很有趣。一些易于使用且非常强大的东西 ;-)

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.