Puoi usare globstar.
Con l' globstaropzione shell abilitata, tutto ciò che serve è gzip -vk **/*.{css,html}.
La shell Bash ha globstarun'opzione che ti consente di scrivere globi ricorsivi con **. shopt -s globstarlo abilita. Ma potresti non voler farlo per altri comandi che esegui in seguito, quindi puoi eseguirlo e il tuo gzip comando in una subshell .
Questo comando gzipè tutto .csse .htmlfile nella directory corrente una delle sue sottodirectory, una qualsiasi delle loro sottodirectory, ecc., Mantenendo i file originali ( -k) e raccontandoti cosa sta facendo ( -v):
(shopt -s globstar; gzip -vk **/*.{css,html})
Se si desidera abbinare i nomi dei file senza distinzione tra maiuscole e minuscole in modo da includere quelle estensioni con alcune o tutte le lettere maiuscole, è possibile anche abilitare l' nocaseglobopzione shell:
(shopt -s globstar nocaseglob; gzip -vk **/*.{css,html})
;separa i due comandi e l'esterno fa ( )sì che vengano eseguiti in una subshell. L'impostazione di un'opzione shell in una subshell non comporta l'impostazione nella shell chiamante. Se non desidera abilitare globstarallora si può eseguire shopt -s globstar; quindi puoi semplicemente eseguire il comando:
gzip -vk **/*.{css,html}
Puoi disabilitare globstarcon shopt -u globstar. Puoi verificare se è attualmente abilitato con shopt globstar.
Come funziona
La chiave per il funzionamento di questo gzipcomando è che la shell esegue espansioni su di esso per produrre un elenco di ciascun file nella gerarchia di directory con un nome corrispondente, quindi passa ciascuno di questi nomi di file come argomenti a gzip.
- L'espansione del controvento si trasforma
**/*.{css,html}in **/*.css **/*.html.
- Quindi il globbing espande questi due modelli nei nomi dei file accessibili nella directory corrente (
**, a causa di globstar) i cui nomi di file sono costituiti da qualcosa ( *) seguito dal suffisso specificato ( .csso .htmlin questo caso).
Questo non corrisponde ai file i cui nomi iniziano con. o quelli che risiedono nelle directory denominate in questo modo. Probabilmente non hai tali file HTML e CSS e, se lo fai, probabilmente non vuoi includerli. Ma se vuoi includerli, puoi abbinarli esplicitamente a seconda delle tue esigenze. Ad esempio, il passaggio **/*.{css,html}a **/{,.}*.{css,html}include i file che iniziano con .mentre non si cerca ancora nelle cartelle che lo fanno.
Se vuoi che siano inclusi sia i file i cui nomi iniziano .che i file nelle directory i cui nomi iniziano con ., c'è un modo più semplice e pulito: abilita l' dotglobopzione shell.
(shopt -s globstar dotglob; gzip -vk **/*.{css,html})
O se si desidera la corrispondenza senza distinzione tra maiuscole e minuscole e la corrispondenza dei nomi di file che iniziano con .:
(shopt -s globstar nocaseglob dotglob; gzip -vk **/*.{css,html})
È possibile, sebbene molto raro, **espandersi a qualcosa di troppo lungo.
Se si dispone di un numero enorme di file denominati in questo modo, ciò potrebbe non riuscire con un messaggio di errore che spiega che la shell non può costruire la riga di comando perché sarebbe troppo lunga. (Anche con migliaia di file, questo di solito non è un problema.)
gzip non verrà chiamato affatto, quindi non otterrai un lavoro a metà.
Se si verifica questo errore, o se sei preoccupato, puoi usarlo findcon -exec, come descrive steeldriver (con {} \;) o come descrivo di seguito (con {} +).
È possibile utilizzare findcon l' -execazione e +per l'efficienza.
Il gzipcomando supporta l'assegnazione di nomi di più file da comprimere. Ma questo findcomando, sebbene funzioni bene e non sarà lento a meno che tu non abbia molti file, esegue il gzipcomando una volta per ogni file:
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} \;
Funziona e puoi sicuramente usarlo. ( .cerca dalla directory corrente. Oltre a questo, è davvero un modo leggermente diverso di scrivere il comando nella risposta molto buona di steeldriver ; puoi usare qualunque stile tu preferisca.)
Puoi anche far findpassare più nomi di file gziped eseguirlo solo tutte le volte necessarie, il che è quasi sempre solo una volta. Per farlo, usa +invece di\; . L' +argomento dovrebbe venire subito dopo {}. findsostituisce +con eventuali nomi di file aggiuntivi.
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
Va bene usare +anche se ci sono solo pochi file corrispondenti e, quando ce ne sono molti, può essere notevolmente più veloce di avere una gzipchiamata separata per ogni file.
Come menziona steeldriver , è possibile utilizzare -inameinvece di -nameabbinare i file il cui nome termina come .csso .htmlma con lettere maiuscole diverse. Ciò corrisponde all'abilitazione nocaseglobnel globstarmetodo basato su sopra descritto.
Infine, probabilmente non hai file o directory corrispondenti che iniziano con .. Ma se lo fai, findli include automaticamente. Se si desidera escluderli (come accade con il globstarmetodo basato su dettagliato sopra quando dotglobè disattivato), è possibile :
find . -not -path '*/.*' \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
Il globstarmodo basato sopra descritto è più semplice da scrivere, soprattutto se si escludono directory e file che iniziano con ., poiché questo è il valore predefinito.
Cosa non fare ...
I nomi di file possono contenere qualsiasi carattere tranne il separatore di percorso /e il carattere null . Esistono molte tecniche che si rompono su nomi di file strani e di solito sono più complicate delle tecniche che funzionano sempre. Quindi suggerisco di evitarli anche quando sai (o pensi di sapere) che stanno bene nella tua situazione specifica. E ovviamente non devi usarli se potresti avere nomi di file con caratteri che possono essere trattati in modo speciale, compresi gli spazi.
È possibile reindirizzare in modo sicuro l'output di findun altro comando che lo elabora se si utilizza -print0o un'azione simile per indurlo a posizionare un carattere null tra i percorsi anziché una nuova riga e non altrimenti. I nomi dei file possono contenere newline (anche se ti scoraggio dal nominare deliberatamente i file con loro). Un findcomando con l' -printazione - incluso il comando find senza azione esplicita, poiché da allora -printè l'impostazione predefinita - non produce output che può essere convogliato in sicurezza o altrimenti fornito a un altro comando che esegue un'azione sui file.
L'output findprodotto con l' -print0azione può essere tranquillamente reindirizzato xargs -0(il -0flag indica xargsdi prevedere un input separato da null).
-rfunziona come progettato. Da man gzip : viaggiare ricorsivamente nella struttura delle directory. Se uno dei nomi di file specificati sulla riga di comando è una directory , gzip scenderà nella directory e comprimerà tutti i file che trova lì (o li decomprimerà nel caso di gunzip). (enfasi mia)