Это должно помочь определить, что происходит в ответе Джонни , а также ответить на вопрос, почему это работает в Linux, но не в Mac.
Проблема заключается в том, что Mac OS X использует bsdtar
, в то время как большинство систем Linux используют gnutar
.
Вы можете установить gnutar
на Mac с Homebrew, используя brew install gnu-tar
, который будет символическая ссылкаgnutar
в/usr/local/bin
качество gtar
.
Если вы установили gnutar
, то вы можете воспроизвести проблему, используя шаги в ответе Джонни .
$ 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
имеет значение. Как отмечает Джонни в комментариях, 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
Однако в этом случае вы явно не контролируете создание архива, так что --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
, и, поскольку, по-видимому, пакет был упакован gnutar
, при распаковке gnutar
не будет ошибки, но при распаковке будет ошибка bsdtar
.
Для дальнейшего чтения и ссылки, возможно, стоит взглянуть на различия между bsdtar и GNU tar? на Unix.SE.