เทียบเท่ากับ tar -“ --strip-components = 1” ใน unzip หรือไม่


48

ฉันมีสคริปต์ที่แยกไฟล์ tar.gz ไปยังไดเรกทอรีย่อยที่ระบุmysubfolder :

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;

มีวิธีใดที่เทียบเท่าในการทำเช่นนี้กับไฟล์ zip?


2
เพียงใช้ bsdtar
drizzt

คำตอบ:


26

ดังที่ Mathias กล่าวว่าunzipไม่มีตัวเลือกดังกล่าว แต่สคริปต์ทุบตีแบบหนึ่งซับสามารถทำงานได้

ปัญหาคือ: วิธีการที่ดีที่สุดขึ้นอยู่กับเลย์เอาต์เก็บถาวรของคุณ โซลูชันที่ถือว่า dir ระดับบนสุดเดียวจะล้มเหลวอย่างน่าสังเวชหากเนื้อหานั้นอยู่ในรากไฟล์เก็บถาวรโดยตรง (ลองนึกถึง/a/foo /b/foo /fooและความโกลาหลของการลอก/aและ/b)

tar --strip-componentและล้มเหลวเดียวกันที่เกิดขึ้นกับ ไม่มีวิธีแก้ปัญหาที่เหมาะกับทุกขนาด

ดังนั้นเพื่อตัด dir รากสมมติว่ามีเป็นหนึ่ง (และเพียงหนึ่ง):

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"

เพียงตรวจสอบให้แน่ใจว่าไฟล์ / dirs ระดับที่สองไม่มีชื่อเดียวกันของพาเรนต์ระดับบนสุด (ตัวอย่างเช่น/foo/foo) แต่/foo/bar/fooและ/foo/bar/barก็โอเค หากพวกเขาทำหรือคุณต้องการที่จะปลอดภัยคุณสามารถใช้ temp dir สำหรับการสกัด:

temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"

หากคุณกำลังใช้ Bash คุณสามารถทดสอบว่าระดับบนสุดเป็น dir เดียวหรือไม่ใช้:

f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"

เมื่อพูดถึง Bash คุณควรเปิดdotglobเพื่อรวมไฟล์ที่ซ่อนอยู่และคุณสามารถรวมทุกอย่างไว้ในฟังก์ชั่นเดียวที่ใช้งานง่าย:

unzip-strip() (
    local zip=$1
    local dest=${2:-.}
    local temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
    shopt -s dotglob && local f=("$temp"/*) &&
    if (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] ; then
        mv "$temp"/*/* "$dest"
    else
        mv "$temp"/* "$dest"
    fi && rmdir "$temp"/* "$temp"
)

ตอนนี้ใส่ไว้ในของคุณ~/.bashrcหรือ~/.profileและคุณจะไม่ต้องกังวลกับมันอีก เพียงใช้เป็น:

unzip-strip sourcefile.zip mysubfolder

(สังเกตว่ามันจะสร้างmysubfolderให้คุณโดยอัตโนมัติหากไม่มี)


สิ่งนี้จะไม่เปิดเครื่องรูดลงในโครงสร้างไดเรกทอรีที่มีอยู่ตามที่ฉันหวังไว้ (ฉันพยายามใช้. แทนที่โฟลเดอร์โฟลเดอร์) ฉันลงเอยด้วยการคลายซิป (unzip zip-with-top-dir.zip) จากนั้นก็ทำการคัดลอก (cp -rv ที่แยกจากด้านบน-zip-dir / *.)
catgofire

4

ฉันไม่พบตัวเลือกดังกล่าวในหน้าคู่มือunzipดังนั้นฉันจึงกลัวว่าจะเป็นไปไม่ได้ :(

อย่างไรก็ตาม (ขึ้นอยู่กับสถานการณ์) คุณสามารถหลีกเลี่ยงได้ ตัวอย่างเช่นหากคุณแน่ใจว่าไดเรกทอรีระดับบนสุดเท่านั้นในไฟล์ zip มีชื่อfoo-ตามด้วยหมายเลขเวอร์ชันคุณสามารถทำสิ่งนี้ได้:

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder

วิธีการที่ดี แต่ไม่สมบูรณ์เล็กน้อย: คุณจะยังคงมี foo * dir ที่มีเนื้อหาที่ถูกดึงมาแบบเต็ม
MestreLion

ใช่ฉันไม่ได้เพิ่มrm -rf foo-*วัตถุประสงค์เนื่องจากอาจเป็นอันตรายได้ เกิดอะไรขึ้นถ้ามีชื่อโฟลเดอร์อยู่แล้วfoo-bar? โปรดทราบว่าการแยกข้อมูลจะเสร็จสิ้นภายใน/tmpโฟลเดอร์ซึ่งจะถูกทำให้ว่างเปล่าโดยอัตโนมัติเป็นระยะ ๆ
Mathias Bynens

นั่นเป็นสาเหตุที่ฉันถูก จำกัด การใช้งานโดยดำเนินการ&&: ขั้นตอนที่กำหนดจะเกิดขึ้นหากขั้นตอนก่อนหน้านี้ประสบความสำเร็จดังนั้นขั้นตอนสุดท้าย ( rm) จะทำงานเฉพาะเมื่อขั้นตอนทั้งหมดเสร็จสมบูรณ์โดยไม่มีข้อผิดพลาด
MestreLion

2
นั่นเป็นสาเหตุที่ไม่ควรให้ผู้ใช้/tmp/some-hardcoded-folder-nameเป็นโฟลเดอร์ชั่วคราว แต่ควรใช้แทนmktemp: รับประกันได้ว่าจะไม่มีโฟลเดอร์ดังกล่าวอยู่ ตรวจสอบคำตอบของฉันด้านล่าง
MestreLion

1

คุณสามารถใช้-jเส้นทางขยะ (ไม่สร้างไดเรกทอรี) สิ่งนี้แนะนำสำหรับการเก็บถาวรระดับเดียวที่ใช้กันโดยทั่วไป ไฟล์เก็บถาวรที่มีโครงสร้างไดเรกทอรีหลายระดับจะถูกทำให้แบนซึ่งอาจทำให้เกิดการแตกชื่อเพื่อให้ไฟล์แตกออกมา

จากหน้า man ของ unzip:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.