Вы можете использовать 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 {} \;
Это работает, и вы определенно можете его использовать. ( .выполняет поиск в текущем каталоге. Кроме того, это действительно немного другой способ написания команды в очень хорошем ответе Steeldriver ; вы можете использовать любой стиль, который вы предпочитаете.)
Вы также можете findпередать несколько имен файлов gzipи запускать их только столько раз, сколько необходимо - что почти всегда только один раз. Для этого используйте +вместо\; . +Аргумент должен прийти только после того, как {}. findзаменяет +дополнительные имена файлов, если таковые имеются.
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
Его можно использовать, +даже если есть только несколько подходящих файлов, и когда их много, это может быть заметно быстрее, чем отдельный gzipвызов для каждого файла.
Как упоминает Steeldriver , вы можете использовать -inameвместо того, -nameчтобы сопоставлять файлы, имена которых заканчиваются на .cssили, .htmlно с другой прописной буквой . Это соответствует включению nocaseglobв globstarоснованном на методе, описанном выше.
Наконец, у вас, вероятно, нет соответствующих файлов или каталогов, которые начинаются с .. Но если вы делаете, findавтоматически включает их. Если вы хотите исключить их (как это происходит с globstarметодом -base, подробно описанным выше, когда dotglobон выключен), вы можете :
find . -not -path '*/.*' \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
globstarОснованное способ , описанный выше, проще писать, особенно если вы за исключением каталогов и файлов , которые начинаются с ., так как это по умолчанию.
Что не надо делать ...
Имена файлов могут содержать любой символ, кроме разделителя пути /и нулевого символа . Существует много техник, которые ломают странные имена файлов, и они обычно более сложны, чем техники, которые всегда работают. Поэтому я предлагаю избегать их, даже если вы знаете (или думаете, что знаете), что они в вашей конкретной ситуации. И, конечно, вы не должны использовать их, если у вас могут быть имена файлов с символами, которые могут обрабатываться особым образом, включая пробелы.
Можно безопасно передать вывод findдругой команды, которая ее обрабатывает, если вы используете -print0или подобное действие, чтобы заставить его помещать нулевой символ между путями вместо новой строки , и не иначе. Имена файлов могут содержать символы новой строки (хотя я не рекомендую вам сознательно именовать файлы вместе с ними). findКоманда с -printдействием - включая команды найти без каких - либо явных действий, так как то -printпо умолчанию - не производит вывод , который можно безопасно свирель или иной не предусмотрен в другую команду , которая выполняет действие на файлах.
Результат, findполученный с -print0действием, может быть безопасно передан по каналу xargs -0( -0флаг указывает xargsожидать ввода с нулевым разделением).
-rработает как задумано. От man gzip : рекурсивно путешествовать по структуре каталогов. Если какое-либо из имен файлов, указанных в командной строке, является каталогом , gzip спустится в каталог и сожмет все найденные там файлы (или распакует их в случае gunzip). (выделение мое)