我在同事的Bash脚本中看到了以下有趣的tar用法:
`tar cf - * | (cd <dest> ; tar xf - )`
显然它的工作方式与rsync -av相似,但速度更快。问题出现了,怎么样?
-m
编辑:任何人都可以解释为什么这个解决方案应该优于以下内容吗?
cp -rfp * dest
前者更快吗?
答案 0 :(得分:12)
它将存档写入标准输出,然后将其传送到子进程 - 由括号括起 - 更改为不同的目录并从标准输入读取/提取。这就是f
参数后的破折号字符的含义。它基本上将当前目录的所有可见文件和子目录复制到另一个目录。
答案 1 :(得分: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
区别在于硬链接文件。请注意如何使用cp
和tar
单独复制硬链接文件。为了使差异更明显,请查看每个的inode:
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,但这是一个很大的原因,至少如果你有广泛的硬链接文件。
答案 2 :(得分:5)
$ time { tar -cf - * | (cd ../bar; tar -xf - ); } real 0m4.209s user 0m0.724s sys 0m3.380s $ time { cp * ../baz/; } real 0m18.727s user 0m0.644s sys 0m7.127s
$ time { tar -cf - * | (cd ../bar; tar -xf - ); } real 3m44.007s user 0m3.390s sys 0m25.644s $ time { cp * ../baz/; } real 3m11.197s user 0m0.023s sys 0m9.576s
我猜这种现象是高度依赖于文件系统的。如果我是对的,你会发现专门研究众多小文件的文件系统(例如reiserfs 3.6)与处理大文件的文件系统之间存在巨大差异。
(我在HFS +上运行了上述测试。)
答案 3 :(得分:2)
这是管道的独特用法。基本上,第一个tar通常直接写入文件,但是它会写入stdout( - ),然后重定向到另一个tar,它接受stdin而不是文件。基本上这与tar文件相关并稍后解压,除非中间没有文件。
答案 4 :(得分:2)
PowerTools书的副本为:
tar cf - * | (cd <dest> && tar xvBf - )
'&amp;&amp;'是一个检查前一个命令的返回码的条件。也就是说,如果“cd”失败,则不会执行“tar xf - ”。我总是抛出-v(详细)和-B(重新输入)。
我一直使用tar。它对于复制到远程系统特别有用,例如:
tar cvf - 。 | ssh someone @ somemachine'(cd some some&amp;&amp; tar xBf - )'
答案 5 :(得分:1)
tar cf - * | (cd <dest> ; tar xf - )
将所有当前目录的隐藏文件/目录都tar到stdout,然后将其汇总到新的子shell中.stdin。该shell首先将当前工作目录更改为<dest>
,然后将其解压缩到该目录。
答案 6 :(得分:1)
某些旧版本的cp没有-f / -p(和类似的)选项来保留权限,所以这个tar技巧完成了这项工作。
答案 7 :(得分:1)
我相信tar会对深度嵌套的目录进行Windows风格的“合并”操作,而cp会覆盖子目录。
例如,如果你有布局:
dir/subdir/file1
并将其复制到包含以下内容的目的地:
dir/subdir/file2
然后通过复制,您将留下:
dir/subdir/file1
但是使用tar命令,您的目标将包含:
dir/subdir/file1
dir/subdir/file2
答案 8 :(得分:0)
tar cf - *
这使用tar将*发送到stdout
|
这显然将stdout重定向到......
(cd <dest> ; tar xf - )
这会将PWD更改为适当的位置,然后从stdin中提取
我不知道为什么这会比rsync更快,因为不涉及压缩。
答案 9 :(得分:0)
tar解决方案将保留符号链接,而cp只会复制并销毁链接。
tar一直是标准的Unix实用程序,比rsync长很多。当目录层次结构需要复制到另一个位置(甚至是另一台计算机)时,您更有可能找到它。 rsync现在可能更容易使用,但速度较慢,因为它比较源和目标并同步它们。 tar只是向一个方向复制。
答案 10 :(得分:0)
如果您有GNU cp
(所有基于Linux的系统都会这样),cp --archive
即可在硬链接文件上运行,也不需要tar。
答案 11 :(得分:0)
碰巧,一位同事在我们的一个脚本中编写了一个几乎相同的命令。在我花了一些时间困惑之后,我问他为什么使用它而不是cp
。我记得他的回答是,当从一个文件系统复制到另一个文件系统时,cp
速度很慢。
这是否属实是需要比我在这个问题上花费更多的测试,但它有一定的意义。第一个tar
进程尽可能快地从源设备读取,只等待该设备读取。同时,第二个tar
进程从其输入管道读取并尽快写入。它可能必须等待输入,但如果目标设备上的写入比源设备上的读取慢,则它只会在目标设备上等待。单个cp
命令必须在源设备和目标设备上等待。
另一方面,现代操作系统在预缓存IO操作方面做得非常好。完全有可能cp
将花费大部分时间等待写入并从内存而不是设备本身进行读取。似乎需要使用两个tar
命令而不是更简单的cp
命令来选择真正可靠的数据。