12

我在同事的 Bash 脚本中看到了以下有趣的 tar 用法:

`tar cf - * | (cd <dest> ; tar xf - )`

显然它的工作原理很像 rsync -av ,但速度更快。问题来了,怎么做?

-m


编辑:谁能解释为什么这个解决方案比以下解决方案更可取?

cp -rfp * dest

前者更快吗?

4

12 回答 12

13

它将归档写入标准输出,然后通过管道将其传送到一个子进程——用括号包裹——该子进程更改为不同的目录并从标准输入中读取/提取。这就是f参数后的破折号字符的含义。它基本上是将当前目录的所有可见文件和子目录复制到另一个目录。

于 2008-11-25T01:11:56.163 回答
9

关于 cp 和 tar 复制目录层次结构的区别,可以做一个简单的实验来说明区别:

alastair box:~/hack/cptest [1134]% mkdir src
alastair box:~/hack/cptest [1135]% cd src
alastair box:~/hack/cptest/src [1136]% touch foo
alastair box:~/hack/cptest/src [1137]% ln -s foo foo-s
alastair box:~/hack/cptest/src [1138]% ln foo foo-h
alastair box:~/hack/cptest/src [1139]% ls -a
total 0
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo-h
lrwxrwxrwx  1 alastair alastair    3 Nov 25 14:59 foo-s -> foo
alastair box:~/hack/cptest/src [1142]% mkdir ../cpdest
alastair box:~/hack/cptest/src [1143]% cp -rfp * ../cpdest
alastair box:~/hack/cptest/src [1144]% mkdir ../tardest
alastair box:~/hack/cptest/src [1145]% tar cf - * | (cd ../tardest ; tar xf - )
alastair box:~/hack/cptest/src [1146]% cd ..
alastair box:~/hack/cptest [1147]% ls -l cpdest
total 0
-rw-r--r--  1 alastair alastair    0 Nov 25 14:59 foo
-rw-r--r--  1 alastair alastair    0 Nov 25 14:59 foo-h
lrwxrwxrwx  1 alastair alastair    3 Nov 25 15:00 foo-s -> foo
alastair box:~/hack/cptest [1148]% ls -l tardest
total 0
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo
-rw-r--r--  2 alastair alastair    0 Nov 25 14:59 foo-h
lrwxrwxrwx  1 alastair alastair    3 Nov 25 15:00 foo-s -> foo

区别在于硬链接文件。请注意硬链接文件是如何cptar. 为了使差异更加明显,请查看每个索引节点:

alastair box:~/hack/cptest [1149]% ls -i cpdest
24690722 foo  24690723 foo-h  24690724 foo-s
alastair box:~/hack/cptest [1150]% ls -i tardest
24690801 foo  24690801 foo-h  24690802 foo-s

可能还有其他原因更喜欢 tar,但这是一个很大的原因,至少在您拥有大量硬链接文件的情况下。

于 2008-11-25T04:10:25.850 回答
7

对于包含 25,000 个空文件的目录:

$ 时间 { 焦油 -cf - * | (cd ../bar; 焦油 -xf - ); }
真正的 0m4.209s
用户 0m0.724s
系统 0m3.380s

$ 时间 { cp * ../baz/; }
真正的 0m18.727s
用户 0m0.644s
系统 0m7.127s

对于有 4 个文件的目录,每个文件 1073741824 字节 (1GB)

$ 时间 { 焦油 -cf - * | (cd ../bar; 焦油 -xf - ); }
真正的 3m44.007s
用户 0m3.390s
系统 0m25.644s

$ 时间 { cp * ../baz/; }
真正的 3m11.197s
用户 0m0.023s
系统 0m9.576s

我的猜测是这种现象高度依赖文件系统。如果我是对的,您会发现专门处理大量小文件的文件系统(例如 reiserfs 3.6)与更擅长处理大文件的文件系统之间存在巨大差异。

(我在 HFS+ 上进行了上述测试。)

于 2008-11-25T02:59:40.143 回答
2

这是管道的独特用法。基本上,第一个 tar 通常直接写入文件,但它会写入 stdout(-),然后将其重定向到另一个采用 stdin 而不是文件的 tar。基本上,这与压缩到文件并稍后解压缩相同,只是中间没有文件。

于 2008-11-25T01:13:00.640 回答
2

PowerTools 书的副本如下:

tar cf - * | (cd <dest> && tar xvBf - )

'&&' 是检查前面命令的返回码的条件。也就是说,如果“cd”失败,“tar xf -”将不会被执行。我总是输入一个 -v (详细)和一个 -B (重新阻止输入)。

我一直使用焦油。它对于复制到远程系统特别有用,例如:

焦油 cvf - . | ssh someone@somemachine '(cd 某处 && tar xBf -)'

于 2011-02-13T00:58:21.700 回答
1
tar cf - * | (cd <dest> ; tar xf - )

会将当前目录的所有非隐藏文件/目录 tar 到标准输出,然后将其通过管道传输到新的子外壳的标准输入中。该外壳首先将当前工作目录更改为<dest>,然后将其解压缩到该目录。

于 2008-11-25T01:13:08.360 回答
1

一些旧版本的 cp 没有 -f / -p (和类似的)选项来保留权限,所以这个 tar 技巧就可以了。

于 2008-11-25T03:26:54.003 回答
1

我相信 tar 将使用深度嵌套的目录执行 Windows 风格的“合并”操作,而 cp 将覆盖子目录。

例如,如果您有布局:

dir/subdir/file1

然后将其复制到包含以下内容的目的地:

dir/subdir/file2

然后使用副本,您将得到:

dir/subdir/file1

但是使用 tar 命令,您的目的地将包含:

dir/subdir/file1
dir/subdir/file2
于 2009-09-01T19:28:43.253 回答
0
tar cf - *

这使用 tar 将 * 发送到标准输出

|

这将标准输出的明显重定向到...

(cd <dest> ; tar xf - )

这会将 PWD 更改为适当的位置,然后从标准输入中提取

我不知道为什么这会比 rsync 快,因为不涉及压缩。

于 2008-11-25T01:15:09.027 回答
0

tar 解决方案将保留符号链接,而 cp 只会制作副本并销毁链接。

tar 一直是标准的 Unix 实用程序,比 rsync 长得多。当需要将目录层次结构复制到另一个位置(甚至是另一台计算机)时,您更有可能找到它。rsync 这些天可能更容易使用,但速度较慢,因为它比较源和目标并同步它们。tar 只是向一个方向复制。

于 2008-11-25T05:07:50.243 回答
0

如果您有 GNU cp(所有基于 Linux 的系统都可以),那么cp --archive即使在硬链接文件上也可以使用,并且不需要 tar。

于 2009-01-14T11:40:56.973 回答
0

碰巧的是,一位同事在我们的一个脚本中编写了一个几乎相同的命令。在我花了一些时间对此感到困惑之后,我问他为什么使用它而不是cp. 我记得他的回答是,cp从一个文件系统复制到另一个文件系统时速度很慢。

这是否属实需要比我愿意在这个问题上花费更多的测试,但它有一定的意义。第一个tar进程尽可能快地从源设备读取,只等待该设备读取。同时,第二个tar进程从其输入管道读取并尽快写入。它可能必须等待输入,但如果目标设备上的写入比源设备上的读取慢,它只会在目标设备上等待。单个cp命令必须在源设备和目标设备上等待。

另一方面,现代操作系统在预缓存 IO 操作方面做得很好。完全有可能cp将大部分时间花在等待写入和从内存中读取而不是设备本身上。似乎需要真正可靠的数据来选择使用两个tar命令而不是更直接的cp命令。

于 2009-02-25T00:57:35.727 回答