cpio VS tar和cp

Tim*_*Tim 13 bash tar archive cp

我刚刚了解到cpio有三种模式:copy-out,copy-in和pass-through.

我想知道cpio在tar下的copy-out和copy-in模式下的优点和缺点是什么.何时使用cpio以及何时使用tar更好?

在传递模式下与cp相比的cpio的类似问题.

感谢致敬!

小智 -6

为什么 cpio 比 tar 更好?有很多原因。

  1. cpio 保留硬链接,如果您使用它进行备份,这一点很重要。
  2. cpio 没有那个烦人的文件名长度限制。当然,gnutar 有一个“hack”,允许您使用更长的文件名(它创建一个临时文件,在其中存储真实名称),但它本质上不能移植到非 gnu tar。
  3. 默认情况下,cpio 保留时间戳
  4. 编写脚本时,它可以更好地控制复制哪些文件和不复制哪些文件,因为您必须明确列出要复制的文件。例如,以下哪项更容易阅读和理解?

    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 感觉更干净一些,但命令行选项本质上是不兼容的!

  5. 如果您需要通过繁忙的网络将大量文件从一台计算机快速复制到另一台计算机,则可以并行运行多个 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。

  • -1表示[无耻的复制和粘贴](http://leftsock.net/~kjw/Ramblings/tar_v_cpio.html),没有正确的引用。 (41认同)
  • 这是该源材料的更合适、更直接的版本[由 archive.org 的 Wayback Machine 保存](https://web.archive.org/web/20140216142548/http://leftsock.net/~kjw/Ramblings /tar_v_cpio.html) (5认同)
  • 原来的网址现在是 404,所以也许无耻的复制/粘贴现在是一个有价值的存档:) (4认同)
  • 其中一些说法也是不诚实的,因为只要您对 shell 有一点了解,tar 就可以从管道读取其文件列表。 (3认同)
  • 不仅如此,一堆 tar 示例甚至无法工作。 (2认同)