gzip tous les fichiers avec des extensions spécifiques

11

J'essaie de compresser tous les fichiers sur Ubuntu qui ont l'extension de fichier .css, .html ou .js. dans un répertoire supérieur et tous les sous-répertoires. Je souhaite conserver les fichiers d'origine et écraser le fichier .gz, s'il existe déjà.

Donc, quand j'ai n fichiers, je veux conserver ces n fichiers et créer n fichiers d'archives supplémentaires. Pas seulement un.

J'ai essayé d'exécuter un script qui ressemble à ceci:

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

Premièrement: je dois avoir une ligne dans ce script pour chaque extension de fichier que je veux compresser. C'est bon, mais j'espère trouver une meilleure façon

Deuxième et plus important: cela ne fonctionne pas. Bien que -r doive faire le travail, les sous-répertoires sont inchangés. Le fichier gzip n'est créé que dans le répertoire supérieur.

Qu'est-ce que j'oublie ici?

Btw: Ce qui suit est un bug dans la sortie verbeuse, non? Lors de l'utilisation des options -k et -v

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

La sortie détaillée indique qu'il remplace le fichier, bien que «remplacer» signifie que le fichier d'origine n'existe pas après le remplacement. Quoi qu'il en soit, ce n'est que la sortie.

$ 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
Sadik
la source
1
-rfonctionne comme prévu. Depuis man gzip : parcourez la structure du répertoire de manière récursive. Si l'un des noms de fichiers spécifiés sur la ligne de commande sont des répertoires , gzip descendra dans le répertoire et compressera tous les fichiers qu'il y trouve (ou les décompressera dans le cas de gunzip). (c'est moi qui souligne)
Dennis
D'accord. Donc -r entrerait un répertoire avec le nom XYZ.css. Ensuite, la récursivité n'est pas conçue comme je m'y attendais.
Sadik

Réponses:

7

vous pouvez le faire avec une boucle for pour trouver chaque fichier puis le compresser:

for i in `find | grep -E "\.css$|\.html$"`; do gzip "$i" ; done
mndo
la source
Je vous remercie! Bien que l' -roption ne fonctionne pas -ket -ffonctionne, je peux donc les utiliser comme ceci: pour i dans find | grep -E "\.css$|\.html$"; do gzip -vkf "$ i"; fait`
Sadik
@Sadik: Soyez prudent! Cette approche ne fonctionnera pas si l'un des noms des fichiers contient un espace.
Dennis
Pourriez-vous expliquer pourquoi non?
Sadik
1
@Sadik: `...`fournit une chaîne, pas une liste. forutilise le séparateur de champ interne ( $IFS) pour décider où cette chaîne doit être fractionnée. Par défaut, il se divise en sauts de ligne, tabulations et espaces, donc si vous avez un fichier appelé new style.css, les commandes gzip newet gzip style.cssseront exécutées.
Dennis
1
@Sadik, Dennis a raison, comme solution rapide, vous pouvez exécuter export IFS=$'\n'juste avant la forboucle.
mndo
14

j'utiliserais

find /path/to/dir \( -name '*.css' -o -name '*.html' \) -exec gzip --verbose --keep {} \;

Remplacez-le namepar inamesi vous souhaitez faire correspondre les extensions à la casse (c'est-à-dire inclure .CSSet / ou .HTMLextensions). Vous pouvez omettre le /path/to/dirsi vous souhaitez démarrer la recherche récursive à partir du répertoire actuel.

tournevis
la source
2
Pour ceux qui peuvent s'interroger sur le --keepcommutateur, oui, il entraîne la conservation des fichiers d'origine. Omettez-le si vous souhaitez qu'ils soient supprimés une fois compressés.
Ben Johnson
4

Pour obtenir la liste des fichiers:

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

Et pour compresser tous ces fichiers:

find -type f | grep -P '\.js|\.html|\.css' | tar cvzf archive.gz -T -
le chaos
la source
N'est-ce pas tarla liste des fichiers en sortie find, plutôt que les fichiers eux-mêmes?
Jos
J'ai édité ma question pour préciser que je veux avoir un fichier d'archive pour chaque fichier css, html ou js.
Sadik
2
@Jos no avec l' -Toption tartraite l'entrée en tant que noms de fichiers.
chaos
@chaos Ah, merci. J'ai appris quelque chose aujourd'hui.
Jos
2

J'ai utilisé la réponse de Steeldriver , mais j'aime la compléter avec les options --bestet --force.

cddans n'importe quel dossier et tapez ce code. Tous vos fichiers correspondants seront compressés.

find . \( -name '*.css' -o -name '*.js' \) -exec gzip --verbose --keep --best --force {} \;
  • Utilisez --bestpour le meilleur taux de compression.
  • À utiliser --forcepour remplacer sans demander s'il existe déjà un fichier compressé.
azerafati
la source
1

Vous pouvez utiliser globstar.

Avec l' globstaroption shell activée, tout ce dont vous avez besoin est gzip -vk **/*.{css,html}.

Le shell Bash a une globstaroption qui vous permet d'écrire des globs récursifs avec **. shopt -s globstarle permet. Mais vous ne voudrez peut-être pas le faire pour d'autres commandes que vous exécuterez plus tard, vous pouvez donc l'exécuter et votre gzip commande dans un sous - shell à la place.

Cette commande gzips all .csset .htmlfichiers dans le répertoire courant l'un de ses sous-répertoires, l'un de leurs sous-répertoires, etc., en conservant les fichiers d'origine ( -k) et en vous indiquant ce qu'il fait ( -v):

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

Si vous souhaitez faire correspondre les noms de fichiers sans tenir compte de la casse afin que ces extensions avec certaines ou toutes les lettres en majuscule soient incluses, vous pouvez également activer l' nocasegloboption shell:

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

;sépare les deux commandes, et l'extérieur ( )les fait exécuter dans un sous-shell. La définition d'une option shell dans un sous-shell ne la fait pas être définie dans le shell appelant. Si vous ne voulez activer globstarvous pouvez exécuter shopt -s globstar; alors vous pouvez simplement exécuter la commande:

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

Vous pouvez désactiver globstaravec shopt -u globstar. Vous pouvez vérifier s'il est actuellement activé avec shopt globstar.

Comment ça fonctionne

La clé du fonctionnement de cette gzipcommande est que le shell effectue des extensions pour produire une liste de chaque fichier dans la hiérarchie de répertoires avec un nom correspondant, puis transmet chacun de ces noms de fichiers comme arguments à gzip.

  • L'expansion du corset se transforme **/*.{css,html}en **/*.css **/*.html.
  • Ensuite, le globbing étend ces deux modèles dans les noms de fichiers accessibles sous le répertoire actuel ( **, en raison de globstar) dont les noms de fichiers se composent de n'importe quoi ( *) suivi du suffixe spécifié ( .cssou .htmldans ce cas).

Cela ne correspond pas aux fichiers dont les noms commencent par. ou ceux qui résident dans des répertoires nommés de cette façon. Vous n'avez probablement pas de tels fichiers HTML et CSS et, si vous en avez, vous ne voulez probablement pas les inclure. Mais si vous souhaitez les inclure, vous pouvez les faire correspondre explicitement en fonction de vos besoins. Par exemple, le changement **/*.{css,html}de **/{,.}*.{css,html}inclut les fichiers qui commencent par .tout en ne recherche dans les dossiers qui le font.

Si vous souhaitez inclure à la fois les fichiers dont les noms commencent par .et les fichiers dans les répertoires dont les noms commencent par ., il existe une méthode plus simple et plus simple: activez l' dotgloboption shell.

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

Ou si vous voulez une correspondance insensible à la casse et une correspondance des noms de fichiers commençant par .:

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

Il est possible, bien que très rare, **de s'étendre à quelque chose de trop long.

Si vous avez un grand nombre de fichiers nommés de cette façon, cela peut échouer avec un message d'erreur expliquant que le shell ne peut pas construire la ligne de commande car ce serait trop long. (Même avec des milliers de fichiers, ce n'est généralement pas un problème.)

gzip ne sera pas appelé du tout, donc vous n'obtiendrez pas un travail à moitié fait.

Si cette erreur se produit, ou si cela vous inquiète, vous pouvez utiliser findavec -exec, soit comme le décrit Steeldriver (avec {} \;) ou comme je le décris ci-dessous (avec {} +).

Vous pouvez utiliser findavec l' -execaction et +pour l'efficacité.

La gzipcommande prend en charge les noms de plusieurs fichiers à compresser. Mais cette findcommande, bien qu'elle fonctionne bien et ne sera lente que si vous avez plusieurs fichiers, exécute la gzipcommande une fois pour chaque fichier:

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

Cela fonctionne et vous pouvez certainement l'utiliser. ( .recherche dans le répertoire courant. En plus de cela, c'est vraiment une façon légèrement différente d'écrire la commande dans la très bonne réponse de Steeldriver ; vous pouvez utiliser le style que vous préférez.)

Vous pouvez également faire findpasser plusieurs noms de fichiers gzipet les exécuter autant de fois que nécessaire, ce qui est presque toujours une seule fois. Pour ce faire, utilisez +au lieu de\; . L' +argument devrait venir juste après {}. findremplace +par des noms de fichiers supplémentaires, le cas échéant.

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

C'est très bien à utiliser +même s'il n'y a que quelques fichiers correspondants, et quand il y en a beaucoup, cela peut être sensiblement plus rapide que d'avoir une gzipinvocation distincte pour chaque fichier.

Comme le mentionne Steeldriver , vous pouvez utiliser -inameau lieu de -namepour faire correspondre les fichiers dont le nom se termine comme .cssou .htmlmais avec des majuscules différentes. Cela correspond à l'activation nocaseglobdans la globstarméthode basée sur la description ci-dessus.

Enfin, vous n'avez probablement pas de fichiers ou de répertoires correspondants commençant par .. Mais si vous le faites, findles inclut automatiquement. Si vous souhaitez les exclure (comme cela se produit avec la globstarméthode basée sur les détails ci-dessus lorsque dotglobest désactivé), vous pouvez :

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

La globstarméthode basée sur la description ci-dessus est plus simple à écrire, surtout si vous excluez les répertoires et les fichiers qui commencent par ., car c'est la valeur par défaut.

Que ne pas faire ...

Les noms de fichiers peuvent contenir n'importe quel caractère à l'exception du séparateur de chemin /et du caractère nul . Il existe de nombreuses techniques qui cassent des noms de fichiers étranges, et elles sont généralement plus compliquées que les techniques qui fonctionnent toujours. Je suggère donc de les éviter même si vous savez (ou pensez que vous savez) qu'ils vont bien dans votre situation spécifique. Et bien sûr, vous ne devez pas les utiliser si vous avez des noms de fichiers avec des caractères qui peuvent être traités spécialement, y compris des espaces.

Il est possible de diriger en toute sécurité la sortie de findvers une autre commande qui la traite si vous utilisez -print0ou une action similaire pour lui faire placer un caractère nul entre les chemins au lieu d'une nouvelle ligne , et pas autrement. Les noms de fichiers peuvent contenir des sauts de ligne (bien que je vous décourage de nommer délibérément des fichiers avec eux). Une findcommande avec l' -printaction - y compris les commandes de recherche sans action explicite, car -printc'est la valeur par défaut - ne produit pas de sortie qui peut être canalisée en toute sécurité ou autrement fournie à une autre commande qui exécute une action sur les fichiers.

La sortie findproduite avec l' -print0action peut être canalisée en toute sécurité xargs -0(l' -0indicateur indique xargsd'attendre une entrée séparée par des valeurs nulles).

Eliah Kagan
la source
0

Pour compresser récursivement tous les fichiers d'un dossier / sous-dossier:

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

Dézipper:

gunzip -r `find . -type f -name "*.gz"` 
Naruto_Hokage
la source
Cette méthode basée sur la substitution de commandes se cassera fréquemment et très mal. Le problème est que les noms de fichiers contenant des espaces ou d'autres espaces seront divisés et traités comme plusieurs noms de fichiers. (Ces commandes sont écrites en utilisant la ` `syntaxe, mais le problème s'applique également lors de l'utilisation de la $( )syntaxe.)
Eliah Kagan