gzip всі файли із конкретними розширеннями


11

Я намагаюся зігнути всі файли на ubuntu, які мають розширення .css, .html або .js. у верхньому каталозі та всіх підкаталогах. Я хочу зберегти оригінальні файли і перезаписати .gz файл, якщо він вже є.

Отже, коли у мене є n файлів, я хочу зберегти ці n файлів і створити додаткові n архівні файли. Не лише один.

Я намагався запустити сценарій, який виглядає приблизно так:

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

По-перше: мені потрібно мати один рядок у цьому сценарії для кожного розширення файлу, яке я хочу gzip. Це нормально, але я сподіваюся знайти кращий спосіб

Друге і важливіше: це не працює. Хоча -r повинен виконувати цю роботу, підкаталоги не змінюються. Файл gzip створюється лише у верхній директорії.

Що я тут пропускаю?

Btw: Далі йде помилка у багатослівному висновку, правда? При використанні опції -k і -v

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

Дослідний висновок говорить, що він замінює файл, хоча "заміна" означає, що оригінальний файл не існує після заміни. У всякому разі, це лише вихідна річ.

$ 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. Тоді рекурсія не розрахована так, як я очікував.
Садік

Відповіді:


7

ви можете зробити це за допомогою циклу for, щоб знайти кожен файл, після чого стисніть його:

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

Дякую! Хоча -rваріант не працює, -kі -fвони працюють, тому я можу використовувати їх так: for i in find | grep -E "\.css$|\.html$"; робити gzip -vkf "$ i"; зроблено`
Садік

@Sadik: Будь обережний! Цей підхід не буде працювати, якщо будь-яке ім’я файлів містить пробіл.
Денніс

Чи можете ви пояснити, чому ні?
Садик

1
@Sadik: `...`надає рядок, а не список. forвикористовує внутрішній роздільник поля ( $IFS), щоб вирішити, куди слід поділити цей рядок. За замовчуванням він розбивається на канали ліній, вкладки та пробіли, тому якщо у вас є файл, який називається new style.css, команди gzip newі gzip style.cssбудуть виконуватись.
Денніс

1
@Sadik, Денніс має рацію, тому що швидке вирішення можна виконати 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.
Бен Джонсон

4

Щоб отримати список файлів:

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

І щоб зібрати всі ці файли:

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

Чи не буде це список файлів , як вихід на , а не самі файли? tarfind
Джос

Я відредагував своє запитання, щоб зрозуміти, що я хочу мати архівний файл для кожного файлу css, html або js.
Садик

2
@Jos no з -Tопцією tarобробляє введення як імена файлів.
хаос

@chaos Ах, дякую. Я щось сьогодні дізнався.
Джос

2

Я використовував відповідь steeldriver , але мені подобається доповнити його --bestі --forceпараметрами.

cdу будь-яку папку та введіть цей код. Усі ваші відповідні файли будуть зібрані.

find . \( -name '*.css' -o -name '*.js' \) -exec gzip --verbose --keep --best --force {} \;
  • Використовуйте --bestдля найкращого коефіцієнта стиснення.
  • Використовуйте --forceдля перезапису, не запитуючи, чи вже є gzipped файл.

1

Ви можете використовувати globstar.

Якщо globstarввімкнено опцію оболонки, все що вам потрібно gzip -vk **/*.{css,html}.

Оболонка Bash має globstarопцію, яка дозволяє писати рекурсивні глобуси за допомогою **. shopt -s globstarдозволяє це. Але ви, можливо, не хочете цього робити для інших команд, які ви запускаєте пізніше, тож можете замість цього запустити його та вашу gzip команду в підзарядці .

Ця команда містить gzipусі .cssта .htmlфайли у поточному каталозі будь-яких її підкаталогів, будь-яких їхніх підкаталогів тощо, зберігаючи вихідні файли ( -k) та повідомляючи, що це робить ( -v):

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

Якщо ви хочете зіставити назви файлів без регістру, так що ці розширення з деякими або всіма літерами включаються з великої літери, тоді ви також можете ввімкнути nocaseglobопцію оболонки:

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

;відокремлює дві команди, а зовнішня - ( )спричиняє їх запуск у нижній частині. Якщо встановити параметр оболонки в підзарядці, це не спричинить її встановлення в оболонці виклику. Якщо ви дійсно хочете включити , globstarто ви можете запустити shopt -s globstar; тоді ви можете просто запустити команду:

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

Ви можете відключити за globstarдопомогою shopt -u globstar. Ви можете перевірити, чи це ввімкнено shopt globstar.

Як це працює

Ключовим чином роботи цієї gzipкоманди є те, що оболонка виконує розширення на ній для створення списку кожного файлу в ієрархії каталогів з відповідним іменем, а потім передає кожну з цих імен як аргументи gzip.

  • Розширення брекета перетворюється **/*.{css,html}на **/*.css **/*.html.
  • Потім глобалізація розширює ці два шаблони на імена файлів, доступних у поточному каталозі ( **завдяки 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 {} \;

Це працює, і ви точно можете ним скористатися. ( .пошук із поточного каталогу. Крім того, це дійсно дещо інший спосіб написання команди в дуже гарній відповіді ; ви можете використовувати будь-який стиль, який ви бажаєте.)

Ви також можете findпередати кілька імен файлів gzipі запустити їх лише стільки разів, скільки потрібно - що майже завжди є лише один раз. Для цього використовуйте +замість цього\; . +Аргумент повинен прийти тільки після того, як {}. findзамінює +додаткові назви файлів, якщо такі є.

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

Це чудово використовувати, +навіть якщо є лише кілька файлів, які відповідають, і коли їх багато, це може бути помітно швидше, ніж окремий gzipвиклик для кожного файлу.

Як зазначає steeldriver , ви можете використовувати -inameзамість , -nameщоб відповідати файли, кінець імені , як .cssабо , .htmlале з різною капіталізацією. Це відповідає включенню nocaseglobв globstarописаному вище методі на основі.

Нарешті, ви, мабуть, не маєте файлів чи каталогів, що починаються, які починаються .. Але якщо ви це зробите, findавтоматично їх включайте. Якщо ви хочете їх виключити (як це відбувається із globstarметодом-базування, детально описаним вище, коли dotglobвимкнено), ви можете :

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

globstarЗасноване спосіб , описаний вище, простіше писати, особливо якщо ви за винятком вищезгаданих каталогів і файлів , які починаються з ., так як це за замовчуванням.

Що не робити ...

Імена файлів можуть містити будь-який символ, крім роздільника шляху /та нульового символу . Існує багато методик, які ламаються на дивних іменах, і вони, як правило, складніші, ніж методи, які завжди просто працюють. Тому я пропоную уникати їх навіть тоді, коли ви знаєте (або думаєте, що знаєте), що вони добре у вашій конкретній ситуації. І звичайно, ви не повинні використовувати їх, якщо у вас можуть бути імена файлів із символами, які можуть бути оброблені спеціально, включаючи пробіли.

Можна безпечно передавати висновок findв іншу команду, яка обробляє його, якщо ви використовуєте -print0або подібну дію, щоб змусити його розмістити нульовий символ між шляхами замість нового рядка , а не інакше. Імена файлів можуть містити нові рядки (хоча я заважаю вам навмисно називати файли ними). findКоманда з -printдією - включаючи команди знайти без будь - яких явних дій, так як то -printза замовчуванням - не виробляє висновок , який можна безпечно сопілка чи іншої НЕ передбачено в іншу команду , яка виконує дію на файлах.

Вихід, що findвиробляється за допомогою -print0дії, може бути безпечно переданий xargs -0( -0прапор повідомляє xargsочікувати введення, розділеного на нуль).


0

Для рециркуляції всіх файлів у папку / підпапку:

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

Щоб розпакувати:

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

Цей метод заміни команд часто порушується, і це дуже погано. Проблема полягає в тому, що назви файлів, що містять пробіли або інший пробіл, будуть розділені і розглядаються як кілька імен файлів. (Ці команди написані за допомогою ` `синтаксису, але проблема повністю застосовується і при використанні $( )синтаксису.)
Eliah Kagan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.