Você pode usar globstar.
Com a globstar
opção de shell ativada, tudo que você precisa é gzip -vk **/*.{css,html}
.
O shell Bash tem uma globstar
opção que permite que você escreva recursiva globs com **
. shopt -s globstar
permite. 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 .css
e .html
arquivos 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 nocaseglob
opçã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 globstar
com shopt -u globstar
. Você pode verificar se está ativado no momento shopt globstar
.
Como funciona
A chave de como esse gzip
comando 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 ( .css
ou .html
neste 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 dotglob
opçã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 find
com -exec
, como a steeldriver descreve (com {} \;
) ou como eu descrevo abaixo (com {} +
).
Você pode usar find
com a -exec
ação e +
obter eficiência.
O gzip
comando suporta receber nomes de vários arquivos a serem compactados. Mas este find
comando, embora funcione bem e não seja lento, a menos que você tenha muitos arquivos, executa o gzip
comando 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 find
passar vários nomes de arquivos para gzip
e 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 {}
. find
substitui +
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 gzip
chamada separada para cada arquivo.
Como a steeldriver menciona , é possível usar, em -iname
vez de, -name
para corresponder aos arquivos cujo nome termina como .css
ou .html
mas com letras maiúsculas diferentes. Isso corresponde à habilitação nocaseglob
no globstar
mé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, find
inclui-os automaticamente. Se você deseja excluí- los (como acontece com o globstar
método baseado em detalhes detalhado acima quando dotglob
desativado), você pode :
find . -not -path '*/.*' \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
A globstar
maneira 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 find
para outro comando que a processa se você usar -print0
uma 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 find
comando com a -print
açã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 find
produzida com a -print0
ação pode ser canalizada com segurança xargs -0
(o -0
sinalizador indica xargs
para esperar uma entrada separada por nulo).
-r
funciona 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)