Isso deve ajudar a identificar o que está acontecendo na resposta de Johnny , bem como responder à pergunta de por que isso funciona no Linux, mas não no Mac.
O problema está no fato de o Mac OS X usar bsdtar
, enquanto a maioria dos sistemas Linux usa gnutar
.
Você pode instalar gnutar
em um Mac com Homebrew, usando brew install gnu-tar
, que vai ligar simbolicamente gnutar
em /usr/local/bin
como gtar
.
Se você instalar gnutar
, poderá reproduzir o problema seguindo as etapas na resposta de 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
Então, obviamente, gnutar
arquiva as coisas de maneira diferente, de maneira que causa bsdtar
engasgos com duplicatas. O fato de gtar -ztvf test.tar.gz
indicar que a segunda instância test/a
é arquivada como a link to test/a
é relevante. Como Johnny aponta nos comentários, gnutar
ele armazenará duplicatas como links físicos em vez do arquivo real, que pode ser desativado --hard-dereference
.
Ou seja, você pode fazer o seguinte:
$ 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
No entanto, nesse caso, você obviamente não controla a criação do tarball, portanto --hard-dereference
não é uma opção. Felizmente, com base na resposta do OP , parece que esse problema foi corrigido pelo montante.
No entanto, se alguém mais enfrentar esse problema no futuro e precisar de uma solução rápida ou tiver um mantenedor upstream que não responda, há uma solução alternativa.
Depois de identificar qual é o arquivo duplicado, você pode usar a --fast-read
opção de bsdtar
(observe que essa opção é apenas parte dela bsdtar
, não 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.
Portanto, no exemplo de brinquedo que eu criei após o exemplo de brinquedo na resposta de Johnny , o arquivo duplicado é test/a
. Portanto, você pode evitar esse problema fazendo o seguinte:
# 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
Além disso, gnutar
é perfeitamente feliz descompactar um arquivo com duplicatas criadas por si só, mesmo quando a --hard-dereference
opção não foi usada:
$ rm -r test
$ gtar -xvf test.tar.gz
test/
test/a
test/b
test/a
$ echo $?
0
$ ls test/
a b
Portanto, isso responde à sua pergunta de por que um erro é gerado no Mac, mas não no Linux. (A maioria) das distribuições Linux são fornecidas e gnutar
, como o pacote foi presumivelmente empacotado gnutar
, não haverá erro ao descompactar gnutar
, mas haverá um erro ao descompactar bsdtar
.
Para leituras e referências adicionais, pode-se considerar quais são as diferenças entre o bsdtar e o GNU tar? no Unix.SE.