刚刚了解到cpio有三种模式:copy-out、copy-in和pass-through。
我想知道 cpio 在复制输出和复制输入模式下相对于 tar 的优缺点是什么。什么时候使用 cpio 更好,什么时候使用 tar?
传递模式下的 cpio 与 cp 的类似问题。
谢谢并恭祝安康!
除了通过disrpm或rpm2cpio翻录打开的 RPM 文件之外,我认为没有任何理由使用 cpio ,但在某些极端情况下,cpio 可能比 tar 更可取。
tar和cpio都是竞争归档格式,它们于 1979 年在Unix 版本 7中引入,然后包含在POSIX .1-1988 中,尽管只有 tar 保留在下一个标准 POSIX.1-2001 1中。
Cpio 的文件格式已经改变了好几次,并且在版本之间没有保持完全兼容。例如,现在有二进制文件信息数据的 ASCII 编码表示。
Tar 更广为人知,多年来变得更加通用,并且更有可能在给定系统上得到支持。CPio 仍然在一些领域中使用,例如Red Hat 软件包格式 (RPM),尽管RPM v5(这是公认的晦涩难懂)使用xar而不是 cpio。
两者都存在于大多数类 Unix 系统上,尽管 tar 更常见。以下是Debian 的安装统计信息:
#rank name inst vote old recent no-files (maintainer)
13 tar 189206 172133 3707 13298 68 (Bdale Garbee)
61 cpio 189028 71664 96346 20920 98 (Anibal Monsalve Salazar)
Copy-out:这是用于存档创建,类似于tar -pc
Copy-in:这是用于存档提取,类似于tar -px
直通:这基本上是上述两种情况,类似于tar -pc … |tar -px
但在一个命令中(因此在微观上更快)。它类似于cp -pdr
,尽管 cpio 和(尤其是) tar 都具有更多的可定制性。还要考虑rsync -a
,人们经常忘记它,因为它更通常在网络连接中使用。
我没有比较它们的性能,但我预计它们在 CPU、内存和存档大小(压缩后)方面会非常相似。
如果不是更好的话,TAR(1) 与 cpio() 一样好。有人可以说它实际上比 CPIO 更好,因为它无处不在且经过审查。我们到处都有焦油球一定是有原因的。
为什么cpio比tar好?有很多原因。
在编写脚本时,它可以更好地控制哪些文件被复制和哪些不被复制,因为您必须明确列出要复制的文件。例如,以下哪个更容易阅读和理解?
find . -type f -name '*.sh' -print | cpio -o | gzip >sh.cpio.gz
或在 Solaris 上:
find . -type f -name '*.sh' -print >/tmp/includeme
tar -cf - . -I /tmp/includeme | gzip >sh.tar.gz
或使用 gnutar:
find . -type f -name '*.sh' -print >/tmp/includeme
tar -cf - . --files-from=/tmp/includeme | gzip >sh.tar.gz
这里有几个具体说明:对于大型文件列表,您不能将 find 放在反引号中;命令行长度将被超出;您必须使用中间文件。单独的 find 和 tar 命令本质上更慢,因为这些操作是串行完成的。
考虑这种更复杂的情况,您希望将一棵树完全打包,但一些文件在一个 tar 中,其余文件在另一个中。
find . -depth -print >/tmp/files
egrep '\.sh$' /tmp/files | cpio -o | gzip >with.cpio.gz
egrep -v '\.sh$' /tmp/files | cpio -o | gzip >without.cpio.gz
或在 Solaris 下:
find . -depth -print >/tmp/files
egrep '\.sh$' /tmp/files >/tmp/with
tar -cf - . -I /tmp/with | gzip >with.tar.gz
tar -cf - . /tmp/without | gzip >without.tar.gz
## ^^-- no there's no missing argument here. It's just empty that way
或使用 gnutar:
find . -depth -print >/tmp/files
egrep '\.sh$' /tmp/files >/tmp/with
tar -cf - . -I /tmp/with | gzip >with.tar.gz
tar -cf - . -X /tmp/without | gzip >without.tar.gz
再次,一些注意事项:单独的 find 和 tar 命令本质上是较慢的。创建更多中间文件会造成更多混乱。gnutar 感觉更干净一些,但是命令行选项本质上是不兼容的!
如果您需要通过繁忙的网络将大量文件从一台机器快速复制到另一台机器,您可以并行运行多个 cpio。例如:
find . -depth -print >/tmp/files
split /tmp/files
for F in /tmp/files?? ; do
cat $F | cpio -o | ssh destination "cd /target && cpio -idum" &
done
请注意,如果您可以将输入分成大小均匀的部分,这将有所帮助。我创建了一个名为“npipe”的实用程序来执行此操作。npipe 将从标准输入读取行,并创建 N 个输出管道,并在每行被消耗时将这些行提供给它们。这样,如果第一个条目是一个需要 10 分钟传输的大文件,其余的是需要 2 分钟传输的小文件,那么您就不会因为等待大文件加上后面排队的另外十几个小文件而停滞不前. 这样,您最终会根据需求进行拆分,而不是严格按照文件列表中的行数或字节数进行拆分。类似的功能可以通过 gnu-xargs 的并行分叉功能来完成,除了将参数放在命令行上而不是将它们流式传输到标准输入。
find . -depth -print >/tmp/files
npipe -4 /tmp/files 'cpio -o | ssh destination "cd /target && cpio -idum"'
这怎么更快?为什么不使用 NFS?为什么不使用 rsync?NFS 本来就很慢,但更重要的是,任何单一工具的使用本质上都是单线程的。rsync 读取源树并一次将一个文件写入目标树。如果你有一台多处理器机器(当时我每台机器使用 16cpu),并行写入变得非常重要。我将 8GB 树的复制速度缩短到 30 分钟;那是 4.6MB/秒!当然这听起来很慢,因为 100Mbit 的网络可以轻松做到 5-10MB/秒,但它是 inode 创建时间让它变慢;这棵树中很容易有 500,000 个文件。因此,如果 inode 创建是瓶颈,那么我需要并行化该操作。相比之下,以单线程方式复制文件需要 4 个小时。速度快了 8 倍!
这更快的第二个原因是并行 tcp 管道不太容易受到丢失数据包的影响。如果一个管道因为丢包而停滞不前,其他管道通常不会受到影响。我不确定这有多大的不同,但是对于精细的多线程内核,这可以再次更有效,因为工作负载可以分布在所有那些空闲的 cpu 上
根据我的经验,cpio 总体上比 tar 做得更好,而且参数更便携(参数在 cpio 版本之间不会改变!),尽管它可能在某些系统上找不到(默认情况下在 RedHat 上没有安装) ,但是默认情况下Solaris也不附带gzip。