ฉันมีสคริปต์ที่แยกไฟล์ tar.gz ไปยังไดเรกทอรีย่อยที่ระบุmysubfolder :
mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;
มีวิธีใดที่เทียบเท่าในการทำเช่นนี้กับไฟล์ zip?
ฉันมีสคริปต์ที่แยกไฟล์ tar.gz ไปยังไดเรกทอรีย่อยที่ระบุmysubfolder :
mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;
มีวิธีใดที่เทียบเท่าในการทำเช่นนี้กับไฟล์ zip?
คำตอบ:
ดังที่ 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 มีชื่อfoo-ตามด้วยหมายเลขเวอร์ชันคุณสามารถทำสิ่งนี้ได้:
cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder
rm -rf foo-*วัตถุประสงค์เนื่องจากอาจเป็นอันตรายได้ เกิดอะไรขึ้นถ้ามีชื่อโฟลเดอร์อยู่แล้วfoo-bar? โปรดทราบว่าการแยกข้อมูลจะเสร็จสิ้นภายใน/tmpโฟลเดอร์ซึ่งจะถูกทำให้ว่างเปล่าโดยอัตโนมัติเป็นระยะ ๆ
&&: ขั้นตอนที่กำหนดจะเกิดขึ้นหากขั้นตอนก่อนหน้านี้ประสบความสำเร็จดังนั้นขั้นตอนสุดท้าย ( rm) จะทำงานเฉพาะเมื่อขั้นตอนทั้งหมดเสร็จสมบูรณ์โดยไม่มีข้อผิดพลาด
/tmp/some-hardcoded-folder-nameเป็นโฟลเดอร์ชั่วคราว แต่ควรใช้แทนmktemp: รับประกันได้ว่าจะไม่มีโฟลเดอร์ดังกล่าวอยู่ ตรวจสอบคำตอบของฉันด้านล่าง
คุณสามารถใช้-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).