Questo dovrebbe aiutare a identificare cosa sta succedendo nella risposta di Johnny , così come rispondere alla domanda sul perché questo funziona su Linux ma non su Mac.
Il problema sta nel fatto che Mac OS X lo utilizza bsdtar
, mentre la maggior parte dei sistemi Linux lo utilizza gnutar
.
Puoi installarlo gnutar
su un Mac con Homebrew, usando brew install gnu-tar
, che si collegherà simbolicamente gnutar
a /usr/local/bin
come gtar
.
Se lo installi gnutar
, puoi riprodurre il problema usando i passaggi nella risposta di Johnny .
$ 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
Quindi ovviamente gnutar
archivia le cose in modo diverso in un modo che fa bsdtar
soffocare i duplicati. È gtar -ztvf test.tar.gz
rilevante il fatto che indichi che la seconda istanza di test/a
è archiviata come a link to test/a
. Come sottolinea Johnny nei commenti, i gnutar
duplicati verranno archiviati come collegamenti reali anziché come file effettivo, che può essere disabilitato con --hard-dereference
.
Cioè, potresti fare quanto segue:
$ 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
Tuttavia, in questo caso, ovviamente non controlli la creazione del tarball, quindi --hard-dereference
non è un'opzione. Fortunatamente, in base alla risposta del PO , sembra che questo problema sia stato risolto a monte.
Tuttavia, se qualcun altro si imbatte in questo problema in futuro e ha bisogno di una soluzione rapida o ha un manutentore a monte che non risponde, c'è una soluzione alternativa.
Una volta identificato il file duplicato, è possibile utilizzare l' --fast-read
opzione di bsdtar
(notare che questa opzione è solo una parte di bsdtar
, non 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.
Quindi, nell'esempio giocattolo che ho creato seguendo l'esempio giocattolo nella risposta di Johnny , il file duplicato è test/a
. Pertanto, è possibile evitare questo problema procedendo come segue:
# 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
Si noti, inoltre, che gnutar
è perfettamente felice di decomprimere un archivio con i duplicati che è stato creato da solo, anche quando l' --hard-dereference
opzione non è stata utilizzata:
$ rm -r test
$ gtar -xvf test.tar.gz
test/
test/a
test/b
test/a
$ echo $?
0
$ ls test/
a b
Quindi questo risponde alla tua domanda sul perché viene generato un errore su Mac ma non su Linux. (La maggior parte) distribuzioni Linux vengono fornite con gnutar
, e poiché il tarball è stato presumibilmente impacchettato con gnutar
, non ci saranno errori durante il disimballaggio con gnutar
, ma ci sarà un errore durante il disimballaggio con bsdtar
.
Per ulteriori letture e riferimenti, si potrebbe voler esaminare Quali sono le differenze tra bsdtar e GNU tar? su Unix.SE.