To powinno pomóc zidentyfikować, co się dzieje w odpowiedzi Johnny'ego , a także odpowiedzieć na pytanie, dlaczego działa to w Linuksie, ale nie na Macu.
Problem polega na tym, że używa Mac OS X bsdtar
, podczas gdy większość systemów Linux gnutar
.
Możesz zainstalować gnutar
na komputerze Mac z Homebrew, używając brew install gnu-tar
, który będzie dowiązaniem symbolicznym gnutar
do /usr/local/bin
as gtar
.
Jeśli zainstalujesz gnutar
, możesz odtworzyć problem, wykonując czynności opisane w odpowiedzi Johnny'ego .
$ 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
Więc oczywiście gnutar
archiwizuje rzeczy inaczej, w sposób, który powoduje bsdtar
zadławienie duplikatów. gtar -ztvf test.tar.gz
Istotny jest fakt, który wskazuje, że druga instancja test/a
jest zarchiwizowana jako a link to test/a
. Jak zauważa Johnny w komentarzach, gnutar
będą przechowywać duplikaty jako twarde linki zamiast rzeczywistego pliku, który można wyłączyć --hard-dereference
.
Oznacza to, że możesz wykonać następujące czynności:
$ 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
Jednak w tym przypadku oczywiście nie kontrolujesz tworzenia tarballa, więc --hard-dereference
nie ma takiej opcji. Na szczęście, na podstawie odpowiedzi PO , wydaje się, że problem ten został rozwiązany przez upstream.
Niemniej jednak, jeśli ktokolwiek inny napotka ten problem w przyszłości i potrzebuje szybkiej naprawy lub nie odpowiada na wcześniejszego opiekuna, istnieje obejście tego problemu.
Po określeniu, co to jest zduplikowany plik, możesz skorzystać z --fast-read
opcji bsdtar
(pamiętaj, że ta opcja jest tylko częścią bsdtar
, a nie 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.
Tak więc w przykładzie zabawki, który utworzyłem zgodnie z przykładem zabawki w odpowiedzi Johnny'ego , zduplikowany plik to test/a
. W ten sposób można uniknąć tego problemu, wykonując następujące czynności:
# 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
Należy ponadto pamiętać, że z gnutar
przyjemnością rozpakowuje archiwum z duplikatami, które zostało utworzone przez siebie, nawet jeśli --hard-dereference
nie użyto opcji:
$ rm -r test
$ gtar -xvf test.tar.gz
test/
test/a
test/b
test/a
$ echo $?
0
$ ls test/
a b
Odpowiada to na pytanie, dlaczego błąd jest generowany na Macu, ale nie na Linuksie. (Większość) dystrybucje Linuksa są dostarczane z gnutar
, a ponieważ tarball był prawdopodobnie spakowany gnutar
, nie będzie błędu podczas rozpakowywania gnutar
, ale wystąpi błąd podczas rozpakowywania bsdtar
.
W celu dalszej lektury i odniesienia warto przyjrzeć się różnicom między bsdtar a GNU tar? na Unix.SE.