gzip semua file dengan ekstensi spesifik

11

Saya mencoba gzip semua file di ubuntu yang memiliki ekstensi file .css, .html atau .js. dalam direktori teratas dan semua subdirektori. Saya ingin menyimpan file asli dan menimpa file .gz, jika sudah ada.

Jadi ketika saya memiliki file n, saya ingin menyimpan file n ini dan membuat file arsip n tambahan. Bukan hanya satu.

Percobaan saya adalah menjalankan skrip yang terlihat seperti ini:

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

Pertama: Saya perlu memiliki satu baris di skrip itu untuk setiap ekstensi file yang ingin saya gzip. Tidak apa-apa, tapi saya berharap menemukan cara yang lebih baik

Kedua dan yang lebih penting: Tidak berfungsi. Meskipun -r harus melakukan pekerjaan itu, subdirektori tidak berubah. File gzip hanya dibuat di direktori teratas.

Apa yang kulewatkan di sini?

Btw: Berikut ini adalah bug dalam output verbose, kan? Saat menggunakan opsi -k dan -v

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

Keluaran verbose mengatakan itu menggantikan file, meskipun "ganti" berarti bahwa file asli tidak ada setelah diganti. Bagaimanapun, ini hanya hal keluaran.

$ 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
Sadik
sumber
1
-rberfungsi seperti yang dirancang. Dari man gzip : Jelajahi struktur direktori secara rekursif. Jika salah satu nama file yang ditentukan pada baris perintah adalah direktori , gzip akan turun ke direktori dan kompres semua file yang ditemukannya di sana (atau dekompres mereka dalam kasus gunzip). (penekanan pada saya)
Dennis
Baik. Jadi -r akan memasuki direktori dengan nama XYZ.css. Maka rekursi tidak dirancang seperti yang saya harapkan.
Sadik

Jawaban:

7

Anda dapat melakukannya dengan for loop untuk menemukan setiap file lalu kompres:

for i in `find | grep -E "\.css$|\.html$"`; do gzip "$i" ; done
mndo
sumber
Terima kasih! Meskipun -ropsinya tidak berfungsi, -kdan -fberfungsi, jadi saya bisa menggunakannya seperti ini: for i in find | grep -E "\.css$|\.html$"; do gzip -vkf "$ i"; selesai`
Sadik
@ Sadik: Hati-hati! Pendekatan ini tidak akan berfungsi jika ada nama file yang mengandung spasi.
Dennis
Bisakah Anda jelaskan mengapa tidak?
Sadik
1
@ Sadik: `...`memberikan string, bukan daftar. formenggunakan pemisah bidang internal ( $IFS) untuk memutuskan di mana string harus dipecah. Secara default, itu terbagi pada baris, biji, dan spasi, jadi jika Anda memiliki file yang dipanggil new style.css, perintah gzip newdan gzip style.cssakan dieksekusi.
Dennis
1
@ Sadik, Dennis benar, karena penyelesaian cepat Anda dapat menjalankan export IFS=$'\n'sesaat sebelum forloop.
mndo
14

Saya akan menggunakan

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

Ubah nameke inamejika Anda ingin mencocokkan ekstensi case-insensitive (yaitu, sertakan .CSSdan / atau .HTMLekstensi). Anda dapat menghilangkan /path/to/dirjika Anda ingin memulai pencarian rekursif dari direktori saat ini.

Steeldriver
sumber
2
Bagi mereka yang mungkin bertanya-tanya tentang --keepswitch, ya, itu menyebabkan file asli tetap dipertahankan. Hapus itu jika Anda ingin mereka dihapus setelah di-zip.
Ben Johnson
4

Untuk mendapatkan daftar file:

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

Dan untuk gzip semua file itu:

find -type f | grep -P '\.js|\.html|\.css' | tar cvzf archive.gz -T -
kekacauan
sumber
Bukankah ini taryang daftar file sebagai output dengan find, daripada file sendiri?
Jos
Saya mengedit pertanyaan saya untuk menjelaskan bahwa saya ingin memiliki file arsip untuk setiap file css, html atau js.
Sadik
2
@ Jo no dengan -Topsi tarmemproses input sebagai nama file.
kekacauan
@chaos Ah, terima kasih. Saya belajar sesuatu hari ini.
Jos
2

Saya menggunakan jawaban steeldriver , tetapi saya ingin melengkapinya dengan opsi --bestdan --force.

cdke dalam folder apa pun dan ketik kode ini. Semua file yang cocok Anda akan di-gzip.

find . \( -name '*.css' -o -name '*.js' \) -exec gzip --verbose --keep --best --force {} \;
  • Gunakan --bestuntuk rasio kompresi terbaik.
  • Gunakan --forceuntuk menimpa tanpa bertanya apakah sudah ada file yang di-gzip.
azerafati
sumber
1

Anda bisa menggunakan globstar.

Dengan globstaropsi shell diaktifkan, yang Anda butuhkan adalah gzip -vk **/*.{css,html}.

Bash shell memiliki globstaropsi yang memungkinkan Anda menulis rekursif gumpalan dengan **. shopt -s globstarmemungkinkannya. Tapi Anda mungkin tidak ingin melakukan itu untuk perintah lain yang Anda jalankan nanti, jadi Anda bisa menjalankannya dan gzip perintah Anda dalam subkulit sebagai gantinya.

Perintah ini gzips semua .cssdan .htmlfile dalam direktori saat ini salah satu subdirektorinya, salah mereka subdirektori, dll, menjaga file asli ( -k) dan memberitahu Anda apa yang dilakukannya ( -v):

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

Jika Anda ingin mencocokkan nama file dengan case-insensitive sehingga ekstensi dengan beberapa atau semua huruf besar disertakan, maka Anda juga dapat mengaktifkan nocaseglobopsi shell:

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

;memisahkan dua perintah, dan bagian luar ( )menyebabkannya dijalankan dalam subkulit. Mengatur opsi shell di subkulit tidak menyebabkannya diatur dalam shell panggilan. Jika Anda tidak ingin mengaktifkan globstarmaka Anda dapat menjalankan shopt -s globstar; maka Anda bisa menjalankan perintah:

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

Anda dapat menonaktifkan globstardengan shopt -u globstar. Anda dapat memeriksa apakah saat ini diaktifkan dengan shopt globstar.

Bagaimana itu bekerja

Kunci untuk bagaimana gzipperintah ini bekerja adalah bahwa shell melakukan ekspansi di atasnya untuk menghasilkan daftar setiap file dalam hierarki direktori dengan nama yang cocok, kemudian melewati masing-masing nama file ini sebagai argumen gzip.

  • Ekspansi brace berubah **/*.{css,html}menjadi **/*.css **/*.html.
  • Kemudian globbing memperluas kedua pola menjadi nama-nama file yang dapat diakses di bawah direktori saat ini ( **, karena globstar) yang nama filenya terdiri dari apa saja ( *) diikuti oleh akhiran yang ditentukan ( .cssatau .htmldalam kasus ini).

Ini tidak cocok dengan file yang namanya dimulai dengan. atau yang berada di direktori bernama cara ini. Anda mungkin tidak memiliki file HTML dan CSS tersebut dan, jika Anda melakukannya, Anda mungkin tidak ingin memasukkannya. Tetapi jika Anda ingin memasukkannya, maka Anda dapat mencocokkannya secara eksplisit tergantung pada kebutuhan Anda. Misalnya, mengubah **/*.{css,html}ke **/{,.}*.{css,html}termasuk file yang dimulai dengan .saat masih belum mencari di folder yang melakukan.

Jika Anda ingin kedua file yang namanya mulai .dan file dalam direktori yang namanya mulai .dimasukkan, ada cara yang lebih bersih dan sederhana: aktifkan dotglobopsi shell.

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

Atau jika Anda ingin pencocokan huruf besar-kecil dan pencocokan nama file yang dimulai dengan .:

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

Mungkin saja, meskipun sangat jarang, untuk **memperluas ke sesuatu yang terlalu lama.

Jika Anda memiliki sejumlah besar file bernama cara ini, maka ini mungkin gagal dengan pesan kesalahan yang menjelaskan bahwa shell tidak dapat membangun baris perintah karena itu akan terlalu lama. (Bahkan dengan ribuan file, ini biasanya tidak masalah.)

gzip tidak akan dipanggil sama sekali, sehingga Anda tidak akan mendapatkan pekerjaan setengah jadi.

Jika kesalahan ini terjadi, atau jika Anda khawatir tentang hal itu, Anda dapat menggunakannya finddengan -exec, seperti yang dijelaskan steeldriver (dengan {} \;) atau seperti yang saya jelaskan di bawah (dengan {} +).

Anda dapat menggunakannya finddengan -execaksi dan +untuk efisiensi.

The gzipmendukung perintah yang diberikan nama-nama beberapa file yang akan dikompresi. Tetapi findperintah ini , meskipun bekerja dengan baik dan tidak akan lambat kecuali jika Anda memiliki banyak file, jalankan gzipperintah sekali untuk setiap file:

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

Ini berfungsi, dan Anda pasti bisa menggunakannya. ( .mencari dari direktori saat ini. Selain itu, ini benar-benar cara menulis perintah dalam jawaban steeldriver yang sangat bagus ; Anda dapat menggunakan gaya apa pun yang Anda inginkan.)

Anda juga dapat membuat findbeberapa nama file lewat gzipdan menjalankannya hanya sebanyak yang diperlukan - yang hampir selalu hanya sekali. Untuk melakukannya, gunakan +sebagai ganti\; . The +Argumen harus datang hanya setelah {}. findganti +dengan nama file tambahan, jika ada.

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

Tidak masalah untuk menggunakan +bahkan jika hanya ada beberapa file yang cocok, dan ketika ada banyak dari mereka, itu bisa terasa lebih cepat daripada memiliki gzipdoa terpisah untuk setiap file.

Seperti disebutkan steeldriver , Anda dapat menggunakan -inamealih-alih -namemencocokkan file yang namanya suka .cssatau .htmltetapi dengan huruf besar berbeda. Ini sesuai dengan mengaktifkan nocaseglobdalam globstarmetode berbasis yang dijelaskan di atas.

Terakhir, Anda mungkin tidak memiliki file atau direktori yang cocok dengan yang dimulai .. Tetapi jika Anda melakukannya, findsecara otomatis memasukkan mereka. Jika Anda ingin mengecualikan mereka (seperti yang terjadi pada globstarmetode -based yang dijelaskan di atas ketika dotglobdimatikan), Anda dapat :

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

Cara globstarberbasis-yang dijelaskan di atas lebih mudah untuk ditulis, terutama jika Anda mengecualikan direktori dan file yang dimulai dengan ., karena itulah defaultnya.

Apa yang tidak boleh dilakukan ...

Nama file dapat berisi karakter apa pun kecuali pemisah jalur /dan karakter nol . Ada banyak teknik yang merusak nama file aneh, dan mereka biasanya lebih rumit daripada teknik yang selalu berhasil. Jadi saya sarankan menghindari mereka bahkan ketika Anda tahu (atau berpikir Anda tahu) mereka baik-baik saja dalam situasi spesifik Anda. Dan tentu saja Anda tidak boleh menggunakannya jika Anda mungkin memiliki nama file dengan karakter yang dapat diperlakukan secara khusus, termasuk spasi.

Dimungkinkan untuk mem-pipe output dengan aman findke perintah lain yang memprosesnya jika Anda menggunakan -print0atau tindakan serupa untuk menyebabkannya menempatkan karakter nol di antara path sebagai ganti baris baru , dan bukan sebaliknya. Nama file dapat berisi baris baru (meskipun saya tidak menyarankan Anda untuk memberi nama file dengan sengaja). Sebuah findperintah dengan -printtindakan - termasuk perintah find dengan tidak ada tindakan eksplisit, sejak itu -printadalah default - tidak menghasilkan output yang aman dapat disalurkan atau diberikan kepada perintah lain yang melakukan tindakan pada file.

Output yang finddihasilkan dengan -print0action dapat dengan aman disalurkan ke xargs -0( -0flag memberitahu xargsuntuk mengharapkan input yang dipisahkan nol).

Eliah Kagan
sumber
0

Untuk zip semua file dalam folder / subfolder secara rekursif:

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

Untuk unzip:

gunzip -r `find . -type f -name "*.gz"` 
Naruto_Hokage
sumber
Metode berbasis substitusi perintah ini akan sering rusak, dan sangat buruk. Masalahnya adalah bahwa nama file yang mengandung spasi atau spasi lain akan dipecah dan diperlakukan sebagai beberapa nama file. (Perintah-perintah ini ditulis menggunakan ` `sintaks, tetapi masalahnya sepenuhnya berlaku ketika menggunakan $( )sintaks juga.)
Eliah Kagan