ฉันมีสคริปต์ที่แยกไฟล์ 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).