Ini akan membantu mengidentifikasi apa yang terjadi dalam jawaban Johnny , serta menjawab pertanyaan mengapa ini bekerja di Linux tetapi tidak untuk Mac.
Masalahnya terletak pada kenyataan bahwa Mac OS X menggunakan bsdtar
, sedangkan sebagian besar sistem Linux menggunakan gnutar
.
Anda dapat menginstal gnutar
pada Mac dengan Homebrew, menggunakan brew install gnu-tar
, yang akan symlink gnutar
ke /usr/local/bin
sebagai gtar
.
Jika Anda menginstal gnutar
, maka Anda dapat mereproduksi masalah menggunakan langkah-langkah dalam jawaban 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
Jadi jelas gnutar
mengarsipkan berbagai hal dengan cara yang menyebabkan bsdtar
tersedak duplikat. Fakta yang gtar -ztvf test.tar.gz
menunjukkan bahwa instance kedua test/a
diarsipkan sebagai link to test/a
relevan. Seperti yang ditunjukkan Johnny dalam komentar, gnutar
akan menyimpan duplikat sebagai tautan keras daripada file yang sebenarnya, yang dapat dinonaktifkan --hard-dereference
.
Artinya, Anda bisa melakukan hal berikut:
$ 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
Namun, dalam hal ini, Anda jelas tidak mengontrol pembuatan tarball, jadi --hard-dereference
bukan pilihan. Untungnya, berdasarkan jawaban OP , tampaknya masalah ini telah diperbaiki oleh hulu.
Meskipun demikian, jika ada orang lain yang mengalami masalah ini di masa depan dan membutuhkan perbaikan cepat atau memiliki pengelola hulu yang tidak responsif, ada solusinya.
Setelah Anda mengidentifikasi apa file duplikat itu, Anda dapat menggunakan --fast-read
opsi bsdtar
(perhatikan bahwa opsi ini hanya bagian dari bsdtar
, bukan 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.
Jadi, dalam contoh mainan yang saya buat mengikuti contoh mainan di jawaban Johnny , file duplikatnya test/a
. Dengan demikian, Anda dapat menghindari masalah ini dengan melakukan hal berikut:
# 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
Catatan, apalagi, yang gnutar
sangat senang membongkar arsip dengan duplikat yang dibuat dengan sendirinya, bahkan ketika --hard-dereference
opsi tidak digunakan:
$ rm -r test
$ gtar -xvf test.tar.gz
test/
test/a
test/b
test/a
$ echo $?
0
$ ls test/
a b
Jadi ini menjawab pertanyaan Anda mengapa ada kesalahan pada Mac tetapi tidak pada Linux. (Sebagian besar) distro Linux dikirim bersama gnutar
, dan karena tarball mungkin dikemas dengan gnutar
, tidak akan ada kesalahan saat membongkar gnutar
, tetapi akan ada kesalahan saat membongkar bsdtar
.
Untuk bacaan dan referensi lebih lanjut, orang mungkin ingin melihat Apa perbedaan antara tar bsdtar dan GNU? di Unix.SE.