gzip tất cả các tệp có phần mở rộng cụ thể


11

Tôi đang cố gzip tất cả các tệp trên ubfox có phần mở rộng tệp .css, .html hoặc .js. trong một thư mục hàng đầu và tất cả các thư mục con. Tôi muốn giữ các tệp gốc và ghi đè lên tệp .gz, nếu đã có.

Vì vậy, khi tôi có n tệp, tôi muốn giữ các tệp n này và tạo thêm n tệp lưu trữ. Không chỉ là một.

Cố gắng của tôi là chạy một kịch bản trông như thế này:

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

Đầu tiên: Tôi cần phải có một dòng trong tập lệnh đó cho mỗi phần mở rộng tập tin mà tôi muốn gzip. Điều đó ổn, nhưng tôi hy vọng sẽ tìm ra cách tốt hơn

Thứ hai và quan trọng hơn: Nó không hoạt động. Mặc dù -r nên thực hiện công việc, các thư mục con không thay đổi. Tệp gzip chỉ được tạo trong thư mục trên cùng.

Tôi đang thiếu gì ở đây?

Btw: Sau đây là một lỗi trong đầu ra dài dòng, phải không? Khi sử dụng tùy chọn -k và -v

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

Đầu ra dài dòng cho biết nó thay thế tệp, mặc dù "thay thế" có nghĩa là tệp gốc không tồn tại sau khi thay thế. Dù sao, đây chỉ là điều đầu ra.

$ 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
-rlàm việc theo thiết kế. Từ man gzip : Du lịch cấu trúc thư mục đệ quy. Nếu bất kỳ tên tệp nào được chỉ định trên dòng lệnh là thư mục , gzip sẽ xuống thư mục và nén tất cả các tệp mà nó tìm thấy ở đó (hoặc giải nén chúng trong trường hợp gunzip). (nhấn mạnh của tôi)
Dennis

Đồng ý. Vì vậy, -r sẽ nhập một thư mục có tên XYZ.css. Sau đó đệ quy không được thiết kế như tôi mong đợi.
Sadik

Câu trả lời:


7

bạn có thể làm điều đó với một vòng lặp for để tìm mọi tệp sau đó nén nó:

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

Cảm ơn bạn! Mặc dù -rtùy chọn không hoạt động -k-fđang hoạt động, vì vậy tôi có thể sử dụng chúng như thế này: for i in find | grep -E "\.css$|\.html$"; làm gzip -vkf "$ i"; xong rồi
Sadik

@Sadik: Cẩn thận! Cách tiếp cận này sẽ không hoạt động nếu bất kỳ tên nào của tệp chứa một khoảng trắng.
Dennis

Bạn có thể giải thích tại sao không?
Sadik

1
@Sadik: `...`cung cấp một chuỗi, không phải là một danh sách. forsử dụng dấu tách trường nội bộ ( $IFS) để quyết định nơi chuỗi đó sẽ được phân chia. Theo mặc định, nó phân chia tại các nguồn cấp dữ liệu, tab và khoảng trắng, vì vậy nếu bạn có một tệp được gọi new style.css, các lệnh gzip newgzip style.csssẽ được thực thi.
Dennis

1
@Sadik, Dennis đúng, vì cách giải quyết nhanh bạn có thể chạy export IFS=$'\n'ngay trước forvòng lặp.
mndo

14

tôi sẽ dùng

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

Thay đổi namethành inamenếu bạn muốn khớp với phần mở rộng không phân biệt chữ hoa chữ thường (nghĩa là bao gồm .CSSvà / hoặc .HTMLphần mở rộng). Bạn có thể bỏ qua /path/to/dirnếu bạn muốn bắt đầu tìm kiếm đệ quy từ thư mục hiện tại.


2
Đối với những người có thể tự hỏi về việc --keepchuyển đổi, vâng, nó làm cho các tập tin gốc được giữ lại. Bỏ qua nếu bạn muốn xóa chúng sau khi được nén.
Ben Johnson

4

Để có được danh sách các tập tin:

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

Và để gzip tất cả các tệp đó:

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

Đây không phải tardanh sách các tệp như đầu ra find, chứ không phải là chính các tệp?
Jos

Tôi đã chỉnh sửa câu hỏi của mình để làm rõ rằng tôi muốn có một tệp lưu trữ cho mỗi tệp css, html hoặc js.
Sadik

2
@ Không có -Ttùy chọn tarxử lý đầu vào dưới dạng tên tệp.
hỗn loạn

@chaos Ah, cảm ơn bạn. Tôi đã học được một cái gì đó ngày hôm nay.
Jos

2

Tôi đã sử dụng câu trả lời của Steeldo , nhưng tôi muốn hoàn thành nó với các tùy chọn --best--force.

cdvào bất kỳ thư mục và nhập mã này. Tất cả các tập tin phù hợp của bạn sẽ được nén.

find . \( -name '*.css' -o -name '*.js' \) -exec gzip --verbose --keep --best --force {} \;
  • Sử dụng --bestcho tỷ lệ nén tốt nhất.
  • Sử dụng --forceđể ghi đè mà không hỏi nếu đã có tệp được nén.

1

Bạn có thể sử dụng globalstar.

Với globstartùy chọn shell được kích hoạt, tất cả những gì bạn cần là gzip -vk **/*.{css,html}.

Các Bash shell có một globstartùy chọn cho phép bạn viết đệ quy globs với **. shopt -s globstarcho phép nó. Nhưng bạn có thể không muốn làm điều đó cho các lệnh khác mà bạn chạy sau đó, vì vậy bạn có thể chạy nó và gzip lệnh của bạn trong một lớp con thay thế.

Lệnh này gziplà tất cả .css.htmlcác tệp trong thư mục hiện tại bất kỳ thư mục con nào, bất kỳ thư mục con nào của chúng , v.v., giữ các tệp gốc ( -k) và cho bạn biết nó đang làm gì ( -v):

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

Nếu bạn muốn khớp tên tệp không phân biệt chữ hoa chữ thường để các phần mở rộng có một số hoặc tất cả các chữ cái viết hoa được bao gồm, thì bạn cũng có thể bật nocaseglobtùy chọn shell:

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

;tách hai lệnh và bên ngoài ( )khiến chúng được chạy trong một lớp con. Đặt tùy chọn shell trong subshell không khiến nó được đặt trong shell gọi. Nếu bạn làm muốn kích hoạt globstarsau đó bạn có thể chạy shopt -s globstar; sau đó bạn có thể chạy lệnh:

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

Bạn có thể vô hiệu hóa globstarvới shopt -u globstar. Bạn có thể kiểm tra nếu nó hiện được kích hoạt với shopt globstar.

Làm thế nào nó hoạt động

Chìa khóa để làm thế nào gziplệnh này hoạt động là shell thực hiện các mở rộng trên nó để tạo ra một danh sách của mỗi tệp trong hệ thống phân cấp thư mục với một tên phù hợp, sau đó chuyển từng tên tệp này làm đối số gzip.

  • Niềng răng mở rộng biến **/*.{css,html}thành **/*.css **/*.html.
  • Sau đó, globalbing mở rộng hai mẫu đó thành tên của các tệp có thể truy cập trong thư mục hiện tại ( **do globstar) tên tệp của nó bao gồm mọi thứ ( *) theo sau là hậu tố được chỉ định ( .csshoặc .htmltrong trường hợp này).

Điều này không khớp với các tệp có tên bắt đầu bằng. hoặc các tệp nằm trong các thư mục được đặt tên theo cách này. Bạn có thể không có bất kỳ tệp HTML và CSS nào như vậy và nếu có, bạn có thể không muốn bao gồm chúng. Nhưng nếu bạn muốn bao gồm chúng, thì bạn có thể kết hợp chúng rõ ràng tùy thuộc vào nhu cầu của bạn. Ví dụ: thay đổi **/*.{css,html}để **/{,.}*.{css,html}bao gồm các tệp bắt đầu .trong khi vẫn không tìm kiếm trong các thư mục.

Nếu bạn muốn cả hai tệp có tên bắt đầu .và tệp trong thư mục có tên bắt đầu .được bao gồm, có một cách đơn giản và đơn giản hơn: bật dotglobtùy chọn shell.

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

Hoặc nếu bạn muốn kết hợp không phân biệt chữ hoa chữ thường khớp tên tệp bắt đầu bằng .:

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

Mặc dù rất hiếm khi có **thể mở rộng sang thứ gì đó quá lâu.

Nếu bạn có một số lượng lớn tệp được đặt tên theo cách này, thì điều này có thể thất bại với thông báo lỗi giải thích rằng trình bao không thể xây dựng dòng lệnh vì nó sẽ quá dài. (Ngay cả với hàng ngàn tệp, điều này thường không phải là vấn đề.)

gzip sẽ không được gọi gì cả, vì vậy bạn sẽ không có được một công việc nửa vời.

Nếu lỗi này xảy ra, hoặc nếu bạn lo lắng về nó, bạn có thể sử dụng findvới -exec, như mô tả thép (với {} \;) hoặc như tôi mô tả bên dưới (với {} +).

Bạn có thể sử dụng findvới các -exechành động và +cho hiệu quả.

Các gziphỗ trợ lệnh được đưa ra tên của nhiều file được nén. Nhưng findlệnh này , mặc dù nó hoạt động tốt và sẽ không bị chậm trừ khi bạn có nhiều tệp, chạy gziplệnh một lần cho mỗi tệp:

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

Điều này hoạt động, và bạn chắc chắn có thể sử dụng nó. ( .tìm kiếm từ thư mục hiện tại. Bên cạnh đó, đó thực sự là một cách viết lệnh hơi khác trong câu trả lời rất hay của Steeldo ; bạn có thể sử dụng bất kỳ kiểu nào bạn thích.)

Bạn cũng có thể findchuyển nhiều tên tệp đến gzipvà chạy nó nhiều lần nếu cần - gần như luôn luôn chỉ một lần. Để làm điều đó, sử dụng +thay vì\; . Cuộc +tranh cãi sẽ đến ngay sau đó {}. findthay thế +bằng tên tệp bổ sung, nếu có.

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

Bạn có thể sử dụng +ngay cả khi chỉ có một vài tệp phù hợp và khi có nhiều tệp trong số đó, có thể nhanh hơn đáng kể so với việc có một lệnh gzipgọi riêng cho mỗi tệp.

Như Steeldo đề cập , bạn có thể sử dụng -inamethay vì -namekhớp các tệp có tên kết thúc giống .csshoặc .htmlvới cách viết hoa khác nhau. Điều này tương ứng với việc kích hoạt nocaseglobtrong globstarphương pháp dựa trên mô tả ở trên.

Cuối cùng, bạn có thể không có bất kỳ tệp hoặc thư mục phù hợp nào bắt đầu bằng .. Nhưng nếu bạn làm, findtự động bao gồm chúng. Nếu bạn muốn loại trừ chúng (như xảy ra với globstarphương pháp dựa trên chi tiết ở trên khi dotglobtắt), bạn có thể :

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

Cách globstardựa trên mô tả ở trên đơn giản hơn để viết, đặc biệt nếu bạn loại trừ các thư mục và tệp bắt đầu ., vì đó là mặc định.

Có gì không để làm ...

Tên tệp có thể chứa bất kỳ ký tự nào ngoại trừ dấu phân cách đường dẫn /ký tự null . Nhiều kỹ thuật phá vỡ tên tập tin kỳ lạ tồn tại và chúng thường phức tạp hơn các kỹ thuật luôn chỉ hoạt động. Vì vậy, tôi khuyên bạn nên tránh chúng ngay cả khi bạn biết (hoặc nghĩ rằng bạn biết) họ vẫn ổn trong tình huống cụ thể của bạn. Và tất nhiên bạn phải không sử dụng chúng nếu bạn có thể có tên tập tin với các nhân vật có thể được điều trị đặc biệt, bao gồm cả khoảng trắng.

Có thể chuyển một cách an toàn đầu ra của findmột lệnh khác xử lý nó nếu bạn sử dụng -print0hoặc một hành động tương tự để khiến nó đặt ký tự null giữa các đường dẫn thay vì một dòng mới , và ngược lại. Tên tệp có thể chứa dòng mới (mặc dù tôi không khuyến khích bạn cố tình đặt tên tệp với chúng). Một findlệnh có -printhành động - bao gồm các lệnh find không có hành động rõ ràng, do đó -printlà mặc định - không tạo ra đầu ra có thể được dẫn một cách an toàn hoặc được cung cấp cho một lệnh khác thực hiện một hành động trên các tệp.

Đầu ra findtạo ra với -print0hành động có thể được dẫn đến một cách an toàn xargs -0( -0cờ cho biết xargsđầu vào được phân tách bằng null).


0

Để nén tất cả các tệp trong một thư mục / thư mục con đệ quy:

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

Để giải nén:

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

Đây thay thế lệnh phương pháp dựa sẽ thường xuyên phá vỡ, và khá nặng. Vấn đề là tên tệp chứa khoảng trắng hoặc khoảng trắng khác sẽ bị phân tách và được coi là nhiều tên tệp. (Các lệnh này được viết bằng ` `cú pháp, nhưng vấn đề cũng được áp dụng hoàn toàn khi sử dụng $( )cú pháp.)
Eliah Kagan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.