Це має допомогти визначити, що відбувається у відповіді Джонні , а також відповісти на питання, чому це працює на 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це не є варіантом. На щастя, виходячи з відповіді ОП , схоже, що ця проблема була виправлена вище за течією.
Тим не менш, якщо хтось інший зіткнеться з цією проблемою в майбутньому і потребує швидкого виправлення або має невідповідний обслуговуючий апарат, який працює вище за течією, існує рішення.
Визначивши, що таке дублікат, ви можете скористатися --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.