Extraction de fichiers .gz contenus dans un dossier

13

J'ai un dossier contenant environ 320116 fichiers .pdb.gz. Je veux tous les décompresser. Si j'utilise gunzip * .gz, cela me donne une erreur, c'est-à-dire une liste d'arguments trop longue. Le dossier fait environ 2 Go. Veuillez me donner une suggestion appropriée.

Lily Sharpton
la source
Si vous devez travailler sur cette structure de répertoire à long terme, divisez ce répertoire en plusieurs. Par exemple, en fonction de l'heure de modification des fichiers ou du nom des fichiers.
dan
Oui, je dois travailler sur le long terme. ils ont été extraits maintenant je veux les subdiviser et les classer en trois dossiers sur la base de leurs noms. Existe-t-il un script shell pour le faire?
Lily Sharpton
Je vous suggère de rechercher des questions similaires là-bas. Si vous n'en trouvez pas pour répondre à vos besoins, posez votre propre nouvelle question.
dan

Réponses:

26
find . -name '*.pdb.gz' -exec gunzip {} +

-exec gunzip {} +fournira gunzipde nombreux mais pas trop de noms de fichiers sur sa ligne de commande. C'est plus efficace que celui -exec gunzip {} \;qui démarre un nouveau gunzipprocessus pour chaque fichier.

John1024
la source
3
Un find, moins gunzip!
dan
2
Notez que le "+" est un GNUisme et ne fonctionnera donc pas sur les systèmes non GNU comme * BSD.
Rétablir Monica - M. Schröder
3
Les versions ultérieures de BSD findautorisent la notation "+". Voir, par exemple, la findpage de manuel de BSD 10.1 . S'applique également à OS X (10.9 et versions ultérieures au moins, peut-être plus tôt).
plasma
7

Chaque fois que vous obtenez des erreurs «liste d'arguments trop longue», vous pouvez contourner ce problème en appelant la commande souhaitée plusieurs fois, à chaque fois avec un sous-ensemble des arguments que vous souhaitez utiliser. xargsest un outil qui vous aide à le faire automatiquement.

find . -type f -a -name \*.pdb.gz -print0 | xargs -0 gunzip
Celada
la source
cela n'a-t-il pas la même inefficacité -execdir gunzip "{}" \;que les xargs invoqueront gunzip séparément pour chaque fichier? C'est ma lecture de la page de manuel.
gogoud
5
Non, xargsremplira autant de noms de fichiers que possible sur la gunzipligne de commande. Essayez! echo a b c d e f | xargs echon'appelle echoqu'une seule fois avec les 6 arguments, vous voyez donc une ligne de sortie (commande assez inutile à exécuter cependant !!!!) tandis que si vous forcez xargsà ne fournir que 3 arguments par appel de la commande, echo a b c d e f | xargs -n 3 echovous obtenez 2 lignes de sortie .
Celada
4
Un autre avantage de l'utilisation xargsest que, avec l' -Poption, vous pouvez exécuter plusieurs gunzipprocessus en parallèle, ce qui (en fonction des paramètres exacts de votre système) peut aller plus vite.
psmears
merci pour le pointeur sur -P, @psmears. Maintenant, j'ai aussi appris quelque chose!
Celada
1

Je pense que cela devrait fonctionner, il transmet le chemin / nom de chaque fichier individuellement à gunzip pour le traitement:

find /my/dir -name "*.pdb.gz" -execdir gunzip "{}" \;
gogoud
la source
1
Cela exécutera gunzip une fois par fichier. Voir la réponse de John1024 pour une manière légèrement différente qui évite cette inefficacité.
Celada
@Celada C'était délibéré; ma préoccupation était que l'utilisation de + pourrait à nouveau conduire à un message d'erreur en raison d'une surcharge de gunzip. Si la méthode de John1024 fonctionne, elle est techniquement plus efficace, mais la mienne devrait fonctionner si ce n'est pas le cas.
gogoud
1
findavec +et xargssont expressément concepteur avec exactement ce problème à l'esprit. Ils fourniront toujours autant d'arguments que possible, sans dépasser la limite du système d'exploitation. Parce que, par ailleurs, il est une limite du système d'exploitation, rien à voir avec gunzip.
Celada
1
@Celada ok merci pour cette information, donc vraisemblablement avec '+' gunzip pourrait être invoqué plus d'une fois, mais moins de 320 000 fois?
gogoud
1
correct.
Celada
1

Essayez de cette façon:

find . -name '*.gz' -exec gunzip {} \;
jherran
la source
3
Cela s'exécutera gunzipune fois par fichier. Voir la réponse de John1024 pour une manière légèrement différente qui évite cette inefficacité.
Celada
Assurez-vous d'échapper au * dans * .gz ...
user253751
1

Si vous avez une machine multicœur, vous verrez probablement que l'utilisation gunzipne va pas maximiser les capacités de votre machine. Pour cela, vous devez exécuter plusieurs gunzips en parallèle. Garder une trace de ce qui est fait dans quel terminal à la main est lourd, mais vous pouvez facilement le faire avec GNU parallel:

find . -name "*.gz" | parallel -X gunzip {}
Anthon
la source
1
Cela ne va-t-il pas échouer parce que la liste des arguments parallelest trop longue?
user253751
@immibis Oui, j'ai oublié le problème d'origine, je mettrai à jour mon message
Anthon
Cela n'échouera- t-il pas encore parce que la liste des arguments findest trop longue?
user253751
1
oui mais vous passez tous les noms de fichiers sur findla ligne de commande de.
user253751
Semble que ce n'est pas un bon jour pour répondre aux questions, j'ai oublié de citer l'argument à-name
Anthon
-1

Il n'est pas nécessaire de l'utiliser findpour cela, car vous n'avez pas mentionné de sous-dossiers. Ce que vous devez faire, c'est:

for f in *.gz;do gunzip $f;done
Tolga Ozses
la source
4
Vous ne devez findsi vous ne voulez pas reproduire 320116 gunzipprocessus, tout comme cette boucle fait.
John WH Smith