这应该有助于确定Johnny的答案中发生了什么,以及回答为什么它在Linux上而不在Mac上有效的问题。
问题在于Mac OS X使用了事实bsdtar
,而大多数Linux系统使用了事实gnutar
。
您可以gnutar
使用brew install gnu-tar
,在带有Homebrew的Mac上进行安装,该符号将链接gnutar
为/usr/local/bin
as gtar
。
如果安装gnutar
,则可以使用Johnny's answer中的步骤重现该问题。
$ brew install gnu-tar
==> Downloading https://homebrew.bintray.com/bottles/gnu-tar-1.28.yosemite.bottle.2.tar.gz
######################################################################## 100.0%
==> Pouring gnu-tar-1.28.yosemite.bottle.2.tar.gz
==> Caveats
gnu-tar has been installed as "gtar".
If you really need to use it as "tar", you can add a "gnubin" directory
to your PATH from your bashrc like:
PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
==> Summary
🍺 /usr/local/Cellar/gnu-tar/1.28: 13 files, 1.6M
$ mkdir test
$ touch test/a test/b
$ gtar -zcvf test.tar.gz test test/a # make the archive with gnutar
test/
test/a
test/b
test/a
$ gtar -ztvf test.tar.gz
drwxr-xr-x adamliter/staff 0 2015-07-28 22:41 test/
-rw-r--r-- adamliter/staff 0 2015-07-28 22:41 test/a
-rw-r--r-- adamliter/staff 0 2015-07-28 22:41 test/b
hrw-r--r-- adamliter/staff 0 2015-07-28 22:41 test/a link to test/a
$ rm -r test
$ tar -xvf test.tar.gz # try to unpack the archive with bsdtar
x test/
x test/a
x test/b
x test/a: Can't create 'test/a'
tar: Error exit delayed from previous errors.
$ echo $?
1
因此,很显然,将内容gnutar
归档的方式会导致bsdtar
重复项阻塞。gtar -ztvf test.tar.gz
令人鼓舞的是,将的第二个实例test/a
存档为a 的事实link to test/a
是相关的。正如Johnny在评论中指出的那样,gnutar
会将重复项存储为硬链接,而不是实际文件,可以使用禁用该链接--hard-dereference
。
也就是说,您可以执行以下操作:
$ mkdir test
$ touch test/a test/b
$ gtar -zcvf test.tar.gz test test/a --hard-dereference
test/
test/a
test/b
test/a
$ gtar -ztvf test.tar.gz test
drwxr-xr-x adamliter/staff 0 2015-07-28 23:49 test/
-rw-r--r-- adamliter/staff 0 2015-07-28 23:49 test/a
-rw-r--r-- adamliter/staff 0 2015-07-28 23:49 test/b
-rw-r--r-- adamliter/staff 0 2015-07-28 23:49 test/a # note that this is no longer a link
$ rm -r test
$ tar -xvf test.tar.gz # unpack with bsdtar
x test/
x test/a
x test/b
x test/a
$ echo $?
0
$ ls test/
a b
但是,在这种情况下,您显然无法控制tarball的创建,因此--hard-dereference
不是一种选择。幸运的是,基于OP的回答,似乎这个问题已由上游解决。
但是,如果将来还有其他人遇到此问题,并且需要快速修复或对上游维护人员没有响应,则可以采取解决方法。
一旦确定了重复文件是什么,就可以使用--fast-read
选项bsdtar
(请注意,该选项仅是的一部分bsdtar
,而不是 gnutar
):
-q (--fast-read)
(x and t mode only) Extract or list only the first archive entry that matches each pattern or filename operand. Exit as soon as each specified pat-
tern or filename has been matched. By default, the archive is always read to the very end, since there can be multiple entries with the same name
and, by convention, later entries overwrite earlier entries. This option is provided as a performance optimization.
因此,在我按照约翰尼的答案中的玩具示例创建的玩具示例中,重复文件为test/a
。因此,您可以通过执行以下操作来避免此问题:
# this set of commands picks up from the first set of commands
# i.e., the following assumes a tarball that was *not* made with
# the --hard-dereference option, although this will work just as well
# with one that was
$ tar -xvqf test.tar.gz test/a # unarchive the first instance of test/a
x test/a
$ tar -xvf test.tar.gz --exclude test/a # unarchive everything except test/a
x test/
x test/b
$ echo $?
0
$ ls test/
a b
请注意,此外,gnutar
即使--hard-dereference
不使用该选项,也很高兴用自己创建的重复文件解压缩存档:
$ rm -r test
$ gtar -xvf test.tar.gz
test/
test/a
test/b
test/a
$ echo $?
0
$ ls test/
a b
因此,这回答了您关于为什么在Mac而不是Linux上引发错误的问题。(大多数)Linux发行版附带gnutar
,并且由于tarball大概是打包在一起的gnutar
,因此,在打开打包时不会有错误gnutar
,但是在打开打包时会出错bsdtar
。
为了进一步阅读和参考,您可能想看看bsdtar和GNU tar有什么区别?在Unix.SE上。