สิ่งนี้จะช่วยระบุสิ่งที่เกิดขึ้น คำตอบของจอห์นนี่ รวมทั้งตอบคำถามว่าทำไมจึงทำงานกับ 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
ถูกเก็บถาวรเป็น 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
อย่างไรก็ตามในกรณีนี้คุณไม่สามารถควบคุมการสร้าง tarball ได้อย่างชัดเจน --hard-dereference
ไม่ใช่ตัวเลือก โชคดีที่ขึ้นอยู่กับ คำตอบของ OP ดูเหมือนว่าปัญหานี้ได้รับการแก้ไขแล้วโดยอัปสตรีม
อย่างไรก็ตามหากใครก็ตามประสบปัญหานี้ในอนาคตและต้องการการแก้ไขอย่างรวดเร็วหรือมีผู้ดูแลอัปสตรีมที่ไม่ตอบสนอง
เมื่อคุณระบุไฟล์ที่ซ้ำกันคุณสามารถใช้ --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 distros มาพร้อมกับ gnutar
และตั้งแต่ tarball ก็น่าจะบรรจุด้วย gnutar
จะไม่มีข้อผิดพลาดเมื่อเปิดออก gnutar
แต่จะมีข้อผิดพลาดเมื่อเปิดออกด้วย bsdtar
.
สำหรับการอ่านและการอ้างอิงเพิ่มเติมคนอาจต้องการดู อะไรคือความแตกต่างระหว่าง bsdtar และ GNU tar? บน Unix.SE