Você pode usar globstar.
Com a globstaropção de shell ativada, tudo que você precisa é gzip -vk **/*.{css,html}.
O shell Bash tem uma globstaropção que permite que você escreva recursiva globs com **. shopt -s globstarpermite. Mas você pode não querer fazer isso para outros comandos executados posteriormente, para que você possa executá-lo e seu gzip comando em uma subshell .
Este comando gzipé tudo .csse .htmlarquivos no diretório atual qualquer de seus subdiretórios, qualquer um de seus subdiretórios, etc., mantendo os arquivos originais ( -k) e dizendo-lhe o que está fazendo ( -v):
(shopt -s globstar; gzip -vk **/*.{css,html})
Se você deseja corresponder os nomes dos arquivos sem distinção entre maiúsculas e minúsculas, para que aquelas extensões com algumas ou todas as letras maiúsculas sejam incluídas, também é possível ativar a nocaseglobopção shell:
(shopt -s globstar nocaseglob; gzip -vk **/*.{css,html})
;separa os dois comandos e o externo ( )faz com que eles sejam executados em um subshell. Definir uma opção de shell em um subshell não faz com que ela seja definida no shell de chamada. Se você não deseja ativar globstar, em seguida, você pode executar shopt -s globstar; então você pode simplesmente executar o comando:
gzip -vk **/*.{css,html}
Você pode desativar globstarcom shopt -u globstar. Você pode verificar se está ativado no momento shopt globstar.
Como funciona
A chave de como esse gzipcomando funciona é que o shell execute expansões nele para produzir uma lista de cada arquivo na hierarquia de diretórios com um nome correspondente e, em seguida, transmita cada um desses nomes de arquivo como argumentos para gzip.
- A expansão da cinta se
**/*.{css,html}transforma **/*.css **/*.html.
- Em seguida, o globbing expande esses dois padrões para os nomes de arquivos acessíveis no diretório atual (
**devido a globstar) cujos nomes de arquivos consistem em qualquer coisa ( *) seguida pelo sufixo especificado ( .cssou .htmlneste caso).
Isso não corresponde aos arquivos cujos nomes começam com. ou aos que residem nos diretórios nomeados dessa maneira. Você provavelmente não possui esses arquivos HTML e CSS e, se tiver, provavelmente não deseja incluí-los. Mas se você quiser incluí-los, poderá correspondê-los explicitamente, dependendo de suas necessidades. Por exemplo, alterar **/*.{css,html}para **/{,.}*.{css,html}inclui arquivos que começam com .ainda não pesquisam nas pastas que o fazem.
Se você deseja que os arquivos cujos nomes começam com .e os diretórios cujos nomes começam .sejam incluídos, existe uma maneira mais limpa e simples: habilite a dotglobopção shell.
(shopt -s globstar dotglob; gzip -vk **/*.{css,html})
Ou se você deseja correspondência que não diferencia maiúsculas de minúsculas e correspondência de nomes de arquivos que começam com .:
(shopt -s globstar nocaseglob dotglob; gzip -vk **/*.{css,html})
É possível, embora muito raro, **expandir para algo muito longo.
Se você tiver um grande número de arquivos nomeados dessa maneira, isso poderá falhar com uma mensagem de erro explicando que o shell não pode criar a linha de comando porque seria muito longo. (Mesmo com milhares de arquivos, isso geralmente não é um problema.)
gzip não será chamado, então você não terá um trabalho pela metade.
Se esse erro ocorrer, ou se você estiver preocupado com isso, poderá usá-lo findcom -exec, como a steeldriver descreve (com {} \;) ou como eu descrevo abaixo (com {} +).
Você pode usar findcom a -execação e +obter eficiência.
O gzipcomando suporta receber nomes de vários arquivos a serem compactados. Mas este findcomando, embora funcione bem e não seja lento, a menos que você tenha muitos arquivos, executa o gzipcomando uma vez para cada arquivo:
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} \;
Isso funciona e você pode definitivamente usá-lo. ( .pesquisa no diretório atual. Além disso, é realmente uma maneira ligeiramente diferente de escrever o comando na resposta muito boa do steeldriver ; você pode usar o estilo que preferir.)
Você também pode findpassar vários nomes de arquivos para gzipe executá-lo apenas quantas vezes forem necessárias - o que é quase sempre apenas uma vez. Para fazer isso, use em +vez de\; . O +argumento deve vir logo depois {}. findsubstitui +por nomes de arquivos adicionais, se houver.
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
É bom usá-lo +mesmo se houver apenas alguns arquivos correspondentes e, quando houver muitos deles, poderá ser visivelmente mais rápido do que ter uma gzipchamada separada para cada arquivo.
Como a steeldriver menciona , é possível usar, em -inamevez de, -namepara corresponder aos arquivos cujo nome termina como .cssou .htmlmas com letras maiúsculas diferentes. Isso corresponde à habilitação nocaseglobno globstarmétodo baseado em descrito acima.
Finalmente, você provavelmente não possui nenhum arquivo ou diretório correspondente que comece com .. Mas se você o fizer, findinclui-os automaticamente. Se você deseja excluí- los (como acontece com o globstarmétodo baseado em detalhes detalhado acima quando dotglobdesativado), você pode :
find . -not -path '*/.*' \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
A globstarmaneira baseada em descrita acima é mais simples de escrever, especialmente se você estiver excluindo diretórios e arquivos que começam com ., pois esse é o padrão.
O que não fazer ...
Os nomes de arquivos podem conter qualquer caractere, exceto o separador de caminho /e o caractere nulo . Existem muitas técnicas que quebram em nomes de arquivos estranhos, e geralmente são mais complicadas do que técnicas que sempre funcionam. Então, sugiro evitá-los, mesmo quando você sabe (ou pensa que sabe) que eles estão bem em sua situação específica. E, é claro, você não deve usá-los se tiver nomes de arquivos com caracteres que possam ser tratados especialmente, incluindo espaços.
É possível canalizar com segurança a saída findpara outro comando que a processa se você usar -print0uma ação semelhante para fazer com que ele coloque um caractere nulo entre os caminhos, em vez de uma nova linha , e não o contrário. Os nomes de arquivos podem conter novas linhas (embora eu o desencoraje de nomear arquivos deliberadamente com eles). Um findcomando com a -printação - incluindo comandos find sem ação explícita, desde então -printé o padrão - não produz saída que possa ser canalizada com segurança ou fornecida de outro modo a outro comando que executa uma ação nos arquivos.
A saída findproduzida com a -print0ação pode ser canalizada com segurança xargs -0(o -0sinalizador indica xargspara esperar uma entrada separada por nulo).
-rfunciona como projetado. No man gzip : Percorra a estrutura de diretórios recursivamente. Se qualquer um dos nomes de arquivos especificados na linha de comando forem diretórios , o gzip descerá para o diretório e compactará todos os arquivos que encontrar lá (ou descompactá-los no caso do gunzip). (ênfase meu)