gzip ไฟล์ทั้งหมดที่มีนามสกุลเฉพาะ


11

ฉันพยายามที่จะ gzip ไฟล์ทั้งหมดในอูบุนตูที่มีนามสกุลไฟล์. css, .html หรือ. js ในไดเรกทอรีบนสุดและไดเรกทอรีย่อยทั้งหมด ฉันต้องการเก็บไฟล์ต้นฉบับและเขียนทับไฟล์. gz หากมีอยู่แล้ว

ดังนั้นเมื่อฉันมี n ไฟล์ฉันต้องการเก็บ n ไฟล์เหล่านี้และสร้างไฟล์เก็บถาวร n เพิ่มเติม ไม่ใช่แค่หนึ่งเดียว

ความพยายามของฉันคือเรียกใช้สคริปต์ที่มีลักษณะดังนี้:

gzip -rkf *.css
gzip -rkf *.html
... one line for each file extension

ก่อน: ฉันต้องมีหนึ่งบรรทัดในสคริปต์นั้นสำหรับแต่ละนามสกุลไฟล์ที่ฉันต้องการ gzip ไม่เป็นไร แต่ฉันหวังว่าจะหาวิธีที่ดีกว่า

ข้อสองและสำคัญกว่า: มันใช้งานไม่ได้ แม้ว่า -r ควรทำงาน แต่ไดเร็กทอรีย่อยจะไม่เปลี่ยนแปลง ไฟล์ gzip ถูกสร้างขึ้นในไดเรกทอรีบนสุดเท่านั้น

ฉันหายไปนี่อะไร

Btw: ต่อไปนี้เป็นข้อบกพร่องในเอาต์พุต verbose ใช่ไหม เมื่อใช้ตัวเลือก -k และ -v

-k, --keep        keep (don't delete) input files
-v, --verbose     verbose mode

เอาต์พุต verbose แจ้งว่าจะแทนที่ไฟล์แม้ว่า "replace" หมายความว่าไฟล์ต้นฉบับไม่มีอยู่หลังจากการแทนที่ อย่างไรก็ตามนี่เป็นเพียงสิ่งที่เอาท์พุท

$ ls
  index.html      subdir1  testfile      testfile.css.gz
  javaclass.java  subdir2  testfile.css
$ gzip -fkv *.css
  testfile.css:   6.6% -- replaced with testfile.css.gz
$ ls
  index.html      subdir1  testfile      testfile.css.gz
  javaclass.java  subdir2  testfile.css

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

ตกลง. ดังนั้น -r จะป้อนไดเรกทอรีที่มีชื่อ XYZ.css การเรียกซ้ำนั้นไม่ได้ออกแบบตามที่ฉันคาดไว้
Sadik

คำตอบ:


7

คุณสามารถทำได้ด้วยการวนรอบเพื่อค้นหาทุกไฟล์แล้วบีบอัดมัน:

for i in `find | grep -E "\.css$|\.html$"`; do gzip "$i" ; done

ขอบคุณ! แม้ว่า-rตัวเลือกจะไม่ทำงาน-kและ-fกำลังทำงานอยู่ดังนั้นฉันจึงสามารถใช้สิ่งนี้ได้: สำหรับฉันในfind | grep -E "\.css$|\.html$"; ทำ gzip -vkf "$ i"; เสร็จแล้ว
Sadik

@Sadik: ระวังด้วย! วิธีการนี้จะไม่ทำงานหากชื่อไฟล์ใด ๆ มีช่องว่าง
Dennis

คุณช่วยอธิบายได้ไหมว่าทำไมไม่
Sadik

1
@Sadik: `...`จัดเตรียมสตริงไม่ใช่รายการ forใช้ตัวคั่นฟิลด์ภายใน ( $IFS) เพื่อตัดสินใจว่าควรแยกสตริงนั้น โดยค่าเริ่มต้นจะแยกที่ linefeeds แท็บและช่องว่างดังนั้นหากคุณมีไฟล์ที่เรียกว่าnew style.cssคำสั่งgzip newและgzip style.cssจะถูกดำเนินการ
Dennis

1
@Sadik, Dennis นั้นถูกต้องเนื่องจากคุณสามารถเรียกใช้export IFS=$'\n'ก่อนที่จะforวนรอบ
mndo

14

ฉันจะใช้

find /path/to/dir \( -name '*.css' -o -name '*.html' \) -exec gzip --verbose --keep {} \;

เปลี่ยนnameเป็นinameหากคุณต้องการจับคู่ส่วนขยายแบบตัวพิมพ์ใหญ่ - เล็ก (เช่นรวม.CSSและ / หรือ.HTMLส่วนขยาย) คุณสามารถละเว้น/path/to/dirถ้าคุณต้องการเริ่มการค้นหาแบบเรียกซ้ำจากไดเรกทอรีปัจจุบัน


2
สำหรับผู้ที่อาจสงสัยเกี่ยวกับ--keepสวิตช์ใช่มันทำให้ไฟล์ต้นฉบับถูกเก็บไว้ งดเว้นหากคุณต้องการให้ลบทิ้งเมื่อ gzipped
Ben Johnson

4

ในการรับรายการไฟล์:

find -type f | grep -P '\.js|\.html|\.css'

และเพื่อ gzip ไฟล์ทั้งหมด:

find -type f | grep -P '\.js|\.html|\.css' | tar cvzf archive.gz -T -

จะไม่นี้รายชื่อของ ไฟล์ที่เป็นผลผลิตจากมากกว่าไฟล์ของตัวเอง? tarfind
Jos

ฉันแก้ไขคำถามของฉันเพื่อให้ชัดเจนว่าฉันต้องการมีไฟล์เก็บถาวรสำหรับไฟล์ css, html หรือ js แต่ละไฟล์
Sadik

2
@Jos no พร้อม-Tตัวเลือกtarประมวลผลอินพุตเป็นชื่อไฟล์
ความโกลาหล

@chaos Ah ขอบคุณ ฉันเรียนรู้บางอย่างในวันนี้
Jos

2

ฉันใช้คำตอบของ steeldriverแต่ฉันชอบที่จะทำมันด้วยตัวเลือก--bestและ--force

cdในโฟลเดอร์ใด ๆ และพิมพ์รหัสนี้ ไฟล์ที่ตรงกันทั้งหมดของคุณจะถูก gzipped

find . \( -name '*.css' -o -name '*.js' \) -exec gzip --verbose --keep --best --force {} \;
  • ใช้--bestสำหรับอัตราส่วนการบีบอัดที่ดีที่สุด
  • ใช้--forceสำหรับการเขียนทับโดยไม่ถามว่ามีไฟล์ gzipped อยู่แล้ว

1

คุณสามารถใช้ globstar

ด้วยตัวเลือกเปลือกเปิดใช้งานทั้งหมดที่คุณต้องการglobstargzip -vk **/*.{css,html}

ทุบตีเปลือกมีglobstarตัวเลือกที่ช่วยให้คุณเขียน recursive globs**กับ shopt -s globstarเปิดใช้งานมัน แต่คุณอาจไม่ต้องการทำเช่นนั้นสำหรับคำสั่งอื่น ๆ ที่คุณเรียกใช้ในภายหลังเพื่อให้คุณสามารถเรียกใช้และgzip คำสั่งของคุณในsubshellแทน

คำสั่งนี้gzipทุกอย่าง.cssและ.htmlไฟล์ในไดเรกทอรีปัจจุบันใด ๆ ของไดเรกทอรีย่อยใด ๆ ของพวกเขาไดเรกทอรีย่อย ฯลฯ , การเก็บรักษาไฟล์ต้นฉบับ ( -k) และบอกคุณว่ามันทำ ( -v):

(shopt -s globstar; gzip -vk **/*.{css,html})

หากคุณต้องการจับคู่ชื่อไฟล์แบบตรงตามตัวพิมพ์ใหญ่เพื่อให้ส่วนขยายเหล่านั้นรวมตัวอักษรบางส่วนหรือทั้งหมดเป็นตัวพิมพ์ใหญ่คุณสามารถเปิดใช้งานnocaseglobตัวเลือกเชลล์ได้:

(shopt -s globstar nocaseglob; gzip -vk **/*.{css,html})

;แยกคำสั่งสองคำสั่งและ( )สาเหตุด้านนอกทำให้คำสั่งเหล่านั้นถูกเรียกใช้ใน subshell การตั้งค่าตัวเลือกของเชลล์ใน subshell ไม่ได้ทำให้มันถูกตั้งค่าในการเรียกเชลล์ หากคุณไม่ต้องการเปิดใช้งานglobstarแล้วคุณสามารถเรียกใช้shopt -s globstar; จากนั้นคุณสามารถเรียกใช้คำสั่ง:

gzip -vk **/*.{css,html}

คุณสามารถปิดการใช้งานด้วยglobstar คุณสามารถตรวจสอบได้หากมีการเปิดใช้งานอยู่ด้วยshopt -u globstarshopt globstar

มันทำงานอย่างไร

กุญแจสำคัญในการวิธีนี้ทำงานคำสั่งว่าการขยายเปลือกดำเนินการเกี่ยวกับมันในการผลิตรายการของแต่ละไฟล์ในลำดับชั้นไดเรกทอรีที่มีชื่อตรงกันแล้วผ่านไปแต่ละชื่อไฟล์เหล่านี้เป็นข้อโต้แย้งgzipgzip

  • การขยายตัวรั้งผลัดกันเข้าไป**/*.{css,html}**/*.css **/*.html
  • จากนั้นglobbingขยายทั้งสองรูปแบบเข้ามาในชื่อของไฟล์ที่สามารถเข้าถึงได้ภายใต้ไดเรกทอรีปัจจุบัน ( **เนื่องจากglobstar) ที่มีชื่อไฟล์ประกอบด้วยอะไร ( *) ตามด้วยคำต่อท้ายที่ระบุ ( .cssหรือ.htmlในกรณีนี้)

สิ่งนี้ไม่ตรงกับไฟล์ที่ชื่อขึ้นต้นด้วย.หรืออยู่ในไดเรกทอรีที่ตั้งชื่อด้วยวิธีนี้ คุณอาจไม่มีไฟล์ HTML และ CSS และคุณอาจไม่ต้องการรวมไฟล์เหล่านั้น แต่ถ้าคุณต้องการที่จะรวมพวกเขาคุณสามารถจับคู่พวกเขาอย่างชัดเจนขึ้นอยู่กับความต้องการของคุณ ตัวอย่างเช่นการเปลี่ยน**/*.{css,html}เป็น**/{,.}*.{css,html}ไฟล์ที่ขึ้นต้นด้วย.ในขณะที่ยังไม่ค้นหาในโฟลเดอร์ที่ทำ

หากคุณต้องการให้ทั้งไฟล์ที่ชื่อขึ้นต้นด้วย.และไฟล์ในไดเรกทอรีที่ชื่อขึ้นต้น.รวมอยู่นั้นจะมีวิธีที่สะอาดกว่าและง่ายกว่า: เปิดใช้งานdotglobตัวเลือกเชลล์

(shopt -s globstar dotglob; gzip -vk **/*.{css,html})

หรือถ้าคุณต้องการที่ตรงกันกรณีตายและการจับคู่ของชื่อไฟล์ที่ขึ้นต้นด้วย.:

(shopt -s globstar nocaseglob dotglob; gzip -vk **/*.{css,html})

เป็นไปได้แม้ว่าจะหายากมากสำหรับ**การขยายไปยังบางสิ่งที่ยาวเกินไป

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

gzip จะไม่ถูกเรียกเลยดังนั้นคุณจะไม่ได้งานที่ทำไปแล้ว

หากข้อผิดพลาดนี้เกิดขึ้นหรือถ้าคุณกังวลเกี่ยวกับเรื่องนี้คุณสามารถใช้findกับ-execได้เช่นกันขณะที่steeldriver อธิบาย (ด้วย{} \;) หรือตามที่ฉันอธิบายด้านล่าง (กับ{} +)

คุณสามารถใช้findกับ-execแอ็คชั่นและ+เพื่อประสิทธิภาพ

gzipชื่อคำสั่งที่ได้รับการสนับสนุนจากหลายไฟล์ที่ถูกบีบอัด แต่findคำสั่งนี้แม้ว่ามันจะทำงานได้ดีและจะไม่ช้าถ้าคุณมีไฟล์จำนวนมากให้รันgzipคำสั่งหนึ่งครั้งสำหรับแต่ละ ไฟล์:

find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} \;

ใช้งานได้และคุณสามารถใช้งานได้อย่างแน่นอน ( .ค้นหาจากไดเรกทอรีปัจจุบันนอกจากนั้นมันเป็นวิธีที่แตกต่างกันเล็กน้อยในการเขียนคำสั่งในคำตอบที่ดีมากของ steeldriverคุณสามารถใช้รูปแบบใดก็ได้ที่คุณต้องการ)

นอกจากนี้คุณยังสามารถfindส่งผ่านชื่อไฟล์หลาย ๆ ไฟล์ไปยังgzipและเรียกใช้ได้หลายครั้งเท่าที่จำเป็นซึ่งเกือบจะแค่ครั้งเดียว จะทำอย่างไรที่จะใช้+\;แทน อาร์กิวเมนต์ควรมาหลัง+ แทนที่ด้วยชื่อไฟล์เพิ่มเติมถ้ามี{}find+

find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +

เป็นการดีที่จะใช้+แม้ว่าจะมีไฟล์ที่ตรงกันเพียงไม่กี่ไฟล์เท่านั้นและเมื่อมีไฟล์จำนวนมากมันก็สามารถสังเกตได้เร็วกว่าการgzipเรียกใช้ไฟล์แยกต่างหากสำหรับแต่ละไฟล์

ในฐานะที่เป็นคนขับรถเหล็กที่กล่าวถึงคุณสามารถใช้-inameแทน-nameการจับคู่ไฟล์ที่มีชื่อเหมือน.cssหรือ.htmlด้วยตัวพิมพ์ใหญ่ที่แตกต่างกัน สิ่งนี้สอดคล้องกับการเปิดใช้งานnocaseglobในglobstarวิธี -based อธิบายไว้ข้างต้น

สุดท้ายคุณอาจไม่ได้ตรงกับไฟล์หรือไดเรกทอรีใด ๆ .ที่เริ่มต้นด้วย แต่ถ้าคุณfindรวมไว้โดยอัตโนมัติ หากคุณต้องการยกเว้นพวกเขา (เช่นเดียวกับที่เกิดขึ้นกับglobstarวิธีการตามรายละเอียดด้านบนเมื่อdotglobปิด) คุณสามารถ :

find . -not -path '*/.*' \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +

globstarวิธีชั่อธิบายไว้ข้างต้นคือง่ายต่อการเขียนโดยเฉพาะอย่างยิ่งถ้าคุณไม่รวมไดเรกทอรีและไฟล์ที่ขึ้นต้นด้วย.ตั้งแต่ที่เริ่มต้น

อะไรไม่ได้ที่จะทำ ...

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

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

เอาต์พุตที่findสร้างขึ้นพร้อมกับ-print0แอ็คชันอาจถูกไพพ์อย่างปลอดภัยxargs -0( -0แฟล็กบอกxargsให้คาดหวังอินพุตที่คั่นด้วย null)


0

หากต้องการ zip ไฟล์ทั้งหมดในโฟลเดอร์ / โฟลเดอร์ย่อยซ้ำ:

gzip -r `find . -type f -name "*.html"` 

หากต้องการเปิดเครื่องรูด:

gunzip -r `find . -type f -name "*.gz"` 

วิธีการทดแทนคำสั่งนี้มักจะผิดพลาดและค่อนข้างแย่ ปัญหาคือชื่อไฟล์ที่มีช่องว่างหรือช่องว่างอื่น ๆ จะถูกแยกและถือว่าเป็นชื่อไฟล์หลายรายการ (คำสั่งเหล่านี้เขียนโดยใช้` `ไวยากรณ์ แต่ปัญหาจะนำไปใช้อย่างสมบูรณ์เมื่อใช้$( )ไวยากรณ์ด้วยเช่นกัน)
Eliah Kagan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.