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