cpio

作者:Eric Goebelbecker

在之前的一篇文章中,我建议使用以下命令来复制文件和目录树

$ find . -depth | cpio -pdmv dest_dir

由于该教程的重点是 find 实用程序,因此我没有深入讨论 cpio

cpio 可以使用八种不同的归档格式(包括 tar)在软盘、磁带或文件中创建和提取归档。它还可以创建目录树的几乎完美的副本,保留文件所有权、模式和访问时间。由于 cpio 旨在接受文件列表,例如 ls 或 find 的输出,因此它比传统的 tar 等工具更适合全面的备份系统;可以轻松地以编程方式控制处理的文件集。

cpio 还有一些不太明显的优点。默认的 cpio 格式比传统的 tar 格式更有效地利用磁带空间,并且它还可以在恢复操作期间跳过损坏的归档部分并继续,而不是完全退出。

GNU tar 将在即将到来的教程中介绍,它解决了许多这些问题。但是,当为没有 GNU 实用程序的其他平台创建归档时,cpio 是一个极好的替代方案。

cpio 未被使用的两个原因显而易见。可能的命令行开关列表几乎占据了半页打字纸,并且由于它不接受文件名或通配符作为参数,因此新手可能会觉得它非常令人生畏。但是 cpio 可能值得付出额外的努力。

cpio 有三种操作模式。直通模式(我在上面的复制示例中使用),创建模式(用于创建归档)和提取模式(用于从归档中提取文件)。

直通模式

顾名思义,在直通模式下,cpio 充当管道,用于将文件列表从一个目的地复制到另一个目的地。在执行此操作的同时,能够根据需要创建子目录并处理特殊文件,这使其成为任何系统管理员都应该熟悉的至关重要的工具。

例如,多用户系统上的一种常见情况是用户目录需要更多驱动器空间。管理员将需要执行以下步骤:向系统添加额外的驱动器,创建一个或多个文件系统,将用户目录从旧文件系统复制到新文件系统,然后,根据具体情况,更改文件系统挂载点,以使过渡不引人注目。

有三种方法可用于将用户的文件复制到新磁盘。一种是使用 tar 归档文件并将它们提取到新区域。这需要归档和提取文件所需的时间。

另一种是使用 cp 的递归模式直接复制它们。此模式仅复制常规文件和链接。它还会跟随符号链接,如果粗心使用,可能会复制大量文件。

当然,很少有系统管理员确切知道用户的目录中有什么。开发人员可能具有特殊文件,例如套接字或管道。任何用户都可能具有带有特殊权限的文件,以防止不必要的访问。管理员没有时间仔细检查主目录,而且许多用户也不希望他们这样做。

$ find . -depth | cpio --pass-through \
 --preserve-modification-times \
 --make-directories --verbose /mnt/export

此命令使 find 输出当前目录下每个文件的名称。(-depth 选项确保在输出目录中的文件名称之前输出目录名称。)cpio 读取这些文件名并将它们复制到 /mnt/export。

传递给 cpio 的开关是

--pass-through在直通模式下操作。

--preserve-modification-times将新文件的修改时间设置为与旧文件相同。

--make-directories在必要时创建目录。(此选项在恢复归档时也有效。)

--verbose详细模式。此模式将为所有文件生成输出。另一种选择是 -dot 选项,该选项仅为每个处理的文件生成一个 .。(这些选项在所有模式下都有效。)

上面的命令创建了原始目录的精确副本,无论文件类型或设置的任何特殊文件模式如何。

如果要将文件复制到同一文件系统,则可以在必要时使用 --link 选项来硬链接文件。

创建模式

创建模式创建归档文件。(这也称为“复制输出”模式。)cpio 接受文件名列表,就像在直通模式下一样。但是,它不是在另一个区域中创建重复文件,而是创建一个归档并将其发送到标准输出。

由于它被发送到标准输出,因此可以将归档重定向到任何设备或文件,例如磁带、软盘或标准文件。

$ find -depth /export/home \
    | cpio --create > /dev/fd0

这将在 /dev/fd0 的软盘驱动器上创建 /export/home 目录树的归档。当然,/export/home 区域可能无法容纳在一张软盘上,但是当每张软盘都装满时,cpio 会提示输入另一个设备或文件名,因此可以更换它,并且用户可以再次键入设备名称。(请注意,仍然建议使用 find 的 -depth 开关,以防止提取归档时可能出现的问题。)

在创建归档时,cpio 有许多选项。最重要的选项之一是归档的格式。

bin(默认)二进制格式以非可移植的方式编码文件。因此,它不适合在 PC 上的 Linux 与 Alpha 或 Power PC 等其他架构上的 Linux 之间交换文件。

odc旧的 (POSIX.1) 可移植格式。这在平台之间是可移植的,但不适用于 inode 超过 65536 的文件系统,这意味着今天的大多数大型硬盘。

newc新的可移植格式。这在平台之间是可移植的,并且对 inode 数量没有固有的限制。

crc新的可移植格式,添加了校验和。

tar与 tar 兼容,但仅支持最多 100 个字符的文件名。

ustar新的 tar 格式。支持最多 255 个字符的文件名。

hpbinHP/UX 使用的不可移植格式。

hpodcHP/UX 使用的“可移植”格式。以不同的方式存储设备文件。

归档格式使用 --format 开关指定。

在所有格式中,crc 格式可能是最好的,因为它具有可移植性,并且通过校验和具有额外的错误检查程度。

创建归档的更好方法是

$ find /export/home -depth | cpio --create \
  --message="Insert next disk and type /dev/fd0 " \
  --format=crc > /dev/fd0

这使用 crc 格式进行归档,并在每张软盘装满时提示用户 插入下一张磁盘并键入 /dev/fd0--message 选项在创建和提取模式下均有效,它会替换默认消息。

还有许多其他选项可用于创建归档,我将在稍后介绍。

即使 GNU tar 确实具有 cpio 的许多优点,但使用 find 指定要备份的文件比 shell 通配符提供了更大的灵活性。[您也可以使用 tar 执行此操作,但是您必须将 find 的输出发送到一个文件,并将该文件用作 tar 的“包含文件”——ED]

提取模式

提取模式(也称为“复制输入”模式)从归档中提取文件。此模式与其他两种模式不一致,因为文件名是在命令行上指定的,而不是通过标准输入上的列表指定的。

$ cpio --extract < /dev/fd0

此命令从 /dev/fd0 中的归档恢复所有文件,因为未指定文件名。如果归档跨越多个卷,则 cpio 将像创建归档时一样提示每个卷。--message 选项可用于覆盖默认消息,就像在创建模式下一样。

cpio 在提取期间自动识别归档格式,因此无需在命令行上指定它们。

find 传递给 cpio 的路径存储在归档中。因此,务必注意如何使用 find。

$ find . -depth | cpio --create > /tmp/archive

这将创建一个归档,该归档将提取到当前工作目录中。

$ find /export/home -depth | cpio --create \
    > /tmp/archive

这将创建一个归档,该归档将尝试提取到 /export/home,而不管情况如何。如果指定了 -d 选项,则会创建目录(如果该目录尚不存在)。(如果 /export/home 不存在并且省略了 -d,则提取将失败。)

在命令行上指定的任何不是选项的内容都被视为文件名模式。

$ cpio --extract "back" < /dev/fd0

这将提取归档中名称中包含 back 的文件。不会恢复其他文件。也可以指定多个模式。

$ cpio --extract "back" "save" < /dev/fd0

这将提取名称中包含“back”或“save”的文件。

除了在命令行上提供模式之外,还可以将它们作为文件中的行提供。该文件使用 --pattern-file=filename 选项指定。这在恢复文件时提供了很大的灵活性,因为不必知道实际路径,也不需要通配符。经常恢复的模式可以存储在一个文件中。

--nonmatching 选项用于指定不提取的文件。

在从中提取任何内容之前,查看归档的内容可能会有所帮助。

$ cpio --list < /dev/fd0

--list 选项列出归档的内容。--numeric-uid-gid 选项强制列表以数字方式显示用户和组 ID,而不是尝试使用 passwd 和 group 文件解析名称。

归档可以发送到文件(或从文件提取),而不是标准输入和输出。

$ find /export/home -depth | cpio --create \
  --file=/vol/archive

此选项可用于创建或提取归档。要使用远程磁带驱动器,请在文件名之前指定主机名和用户名。(用户必须能够无需密码即可访问远程主机。这可以通过使用 .rhosts 文件来完成)

$ find /export/home -depth | cpio --create \
  --file=eric@bajor:/dev/rmt0

使用此选项创建归档的关键优势之一是,使用此选项创建的磁盘文件(不在磁带或软盘上的归档)可以使用 --append 选项附加到它们。

如果 eric 没有密码(不推荐),或者运行命令的主机在 eric 主目录的 .rhosts 文件中列出,则此命令将起作用。

在恢复归档时,有时希望不更改文件修改时间

$ find /export/home -depth | cpio --extract \
  --preserve-modification-times --file
/vol/archive

--preserve-modification-times 选项在提取模式以及直通模式下都有效。

除了保留修改时间外,还可以保留归档或复制文件的访问时间,以便 cpio 操作不会影响原始文件

$ find . -depth | cpio --pass-through \
 --make-directories --preserve-modification-times \
 --reset-access-time /vol/copy

这会将当前目录复制到 /vol/copy,同时将旧文件的修改时间复制到新文件,并且还保持原始文件的访问时间不变。

当在复制输入(提取)或直通模式下操作时,cpio 的默认操作是在覆盖现有文件(如果现有文件较新)之前提示用户进行确认。默认情况下,cpio 不会替换现有文件。--unconditional 选项会覆盖该行为

$ cpio --extract --unconditional "back" "save" \
  < /dev/fd0

--dereference 选项在归档创建和直通模式下复制符号链接指向的文件,而不是链接本身。

--rename 命令将提示用户交互式地重命名每个文件。这仅在提取模式下有效。

当作为系统管理员时,有时可以恢复归档或复制目录,并在过程中更改目标的用户或组 ID。

$ cpio --extract --owner=eric.staff < /dev/fd0

这将恢复 /dev/fd0 上的归档,并将所有提取文件的所有者设置为 eric,组设置为 staff。只有 root 可以使用此选项。如果省略组,则不会更改它,除非包含 .,在这种情况下,组将设置为用户的登录组。

与文件所有权相关的另一个选项是 --no-preserve-owner。这是非 root 用户的默认行为。文件将属于复制或提取它们的用户,而不是原始用户。对于 root 用户,默认设置为保留所有权。

还有与在大端和小端架构之间传输数据以及控制 I/O 缓冲区大小以优化性能相关的高级选项。

总结

cpio 命令乍一看可能显得神秘,但是在使用几次之后,它将成为您 Linux 工具包中不可或缺的补充。特别是如果您是没有磁带驱动器且没有商业备份实用程序的众多用户之一,那么学习 cpio 和更换软盘肯定胜过磁盘崩溃或您在使用 rm 命令时犯错后的(不存在的)替代方案...

Eric Goebelbecker (eric@interramp.com) 是 Reuters America, Inc. 的系统分析师。他为使用市场数据检索和操作 API 的交易室和后台运营客户(主要是金融机构)提供支持。在他的业余时间(每周约 15 分钟...),他阅读哲学并摆弄 Linux。

加载 Disqus 评论