小智 -6
为什么 cpio 比 tar 更好?有很多原因。
编写脚本时,它可以更好地控制复制哪些文件和不复制哪些文件,因为您必须明确列出要复制的文件。例如,以下哪项更容易阅读和理解?
find . -type f -name '*.sh' -print | cpio -o | gzip >sh.cpio.gz
Run Code Online (Sandbox Code Playgroud)
或在 Solaris 上:
find . -type f -name '*.sh' -print >/tmp/includeme
tar -cf - . -I /tmp/includeme | gzip >sh.tar.gz
Run Code Online (Sandbox Code Playgroud)
或使用 gnutar:
find . -type f -name '*.sh' -print >/tmp/includeme
tar -cf - . --files-from=/tmp/includeme | gzip >sh.tar.gz
Run Code Online (Sandbox Code Playgroud)
这里有一些具体的注意事项:对于大型文件列表,您不能将 find 放在反引号中;命令行长度将超出;您必须使用中间文件。单独的 find 和 tar 命令本身速度较慢,因为这些操作是串行完成的。
考虑这种更复杂的情况,您希望完全打包一棵树,但一些文件在一个 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
Run Code Online (Sandbox Code Playgroud)
或在 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
Run Code Online (Sandbox Code Playgroud)
或使用 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
Run Code Online (Sandbox Code Playgroud)
再次强调一些注意事项:单独的 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
Run Code Online (Sandbox Code Playgroud)
请注意,如果您可以将输入分成均匀大小的部分,将会有所帮助。我创建了一个名为“npipe”的实用程序来执行此操作。npipe 将从 stdin 读取行,并创建 N 个输出管道,并在消耗每行时将行提供给它们。这样,如果第一个条目是一个大文件,需要 10 分钟才能传输,而其余的都是小文件,需要 2 分钟才能传输,那么您就不会因为等待大文件以及后面排队的另外十几个小文件而停滞不前。 。这样,您最终会按需求进行拆分,而不是严格按文件列表中的行数或字节数进行拆分。类似的功能可以使用 gnu-xargs 的并行分叉功能来完成,只不过将参数放在命令行上而不是将它们流式传输到标准输入。
find . -depth -print >/tmp/files
npipe -4 /tmp/files 'cpio -o | ssh destination "cd /target && cpio -idum"'
Run Code Online (Sandbox Code Playgroud)
这怎么更快?为什么不使用 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。