Zip tous les fichiers dans le répertoire?

483

Est-il possible de compresser tous les fichiers d'un répertoire donné avec la zipcommande? J'ai entendu parler de l'utilisation *.*, mais je veux que cela fonctionne aussi pour les fichiers sans extension.

tkbx
la source
2
Avez-vous essayé de naviguer au niveau supérieur depuis votre répertoire souhaité et de le faire zip myarch.zip mydir/*?
Joseph R.
13
ou mieuxzip -r myarch.zip mydir/*
Adam
25
ou mieuxzip -r myarch.zip mydir
ctrl-alt-delor
*.*signifie tout fichier avec un point. Dans cp / m et dos, tous les fichiers avaient un point, ce qui vous a fait taper (impossible *). Par conséquent, les gens sont venus voir *.*tous les fichiers. Finalement, Microsoft a ajouté des noms de fichiers longs qui pourraient avoir zéro ou plus de points. Pour trouver un fichier qui a un point sur Windows, vous devez taper *.*.*.
ctrl-alt-delor

Réponses:

705

Vous pouvez simplement utiliser *; il n'y a pas besoin de *.*. Les extensions de fichier ne sont pas spéciales sous Unix. *correspond à zéro ou plusieurs caractères, y compris un point. Donc, ça correspond foo.png, parce que c'est zéro ou plusieurs caractères (sept, pour être exact).

Notez que *par défaut, les fichiers commençant par un point ne correspondent pas *.*. C'est souvent ce que tu veux. Si ce n'est pas le cas, en bash, si vous shopt -s dotgloble ferez (tout en excluant .et ..). D'autres coquilles ont différentes manières (voire aucune) d'inclure des fichiers de points.

Alternativement, a zipaussi une -roption (récursive) pour faire des arbres de répertoires entiers à la fois (sans avoir à vous soucier du problème de fichier de points):

zip -r myfiles.zip mydir

mydirest le répertoire contenant vos fichiers. Notez que le zip produit contiendra la structure de répertoires ainsi que les fichiers. Comme le souligne peterph dans son commentaire, ceci est généralement considéré comme une bonne chose: extraire le zip stockera proprement tous les fichiers extraits dans un seul sous-répertoire.

Vous pouvez également dire à zip de ne pas stocker les chemins avec l' option -j/ --junk-paths.

La zipcommande est livrée avec une documentation vous expliquant toutes ses (nombreuses) options; tapez man zippour voir cette documentation. Ce n'est pas unique à zip; vous pouvez obtenir la documentation pour la plupart des commandes de cette façon.

derobert
la source
9
Vous voudrez peut-être ajouter qu'il est considéré comme une bonne pratique de contenir tout le contenu de l'archive dans un répertoire de niveau supérieur - afin d'éviter de polluer son répertoire actuel lors de l'extraction.
Peter
@peterph fait. Bien que ce soit moins une convention dans les fichiers zip que dans, par exemple, tarfiles, j'ai bien peur.
derobert
Malheureusement oui. Probablement en raison de l'héritage Windows de drag'n'drop à l'héritage desktop et linux de travail avec les codes sources.
Peter
2
Gardez à l'esprit que le *shell-globbing n'inclut pas les fichiers de points (c'est-à-dire les noms de fichiers commençant par .). Ceci est un autre avantage à compresser le répertoire entier par nom.
mrb
Mais utiliser -r inclut le répertoire lui-même, ce qui rompt ce que je fais. Ne comprendrait pas .et ..?
tkbx
11

Dans mon cas, je voulais compresser chaque fichier dans ses propres archives. J'ai donc fait ce qui suit (en zsh):

$ for file in *; do zip ${file%.*}.zip $file; done
Radon Rosborough
la source
1
Il n'y a pas mkvici? De plus, rien ici n'est particulièrement zshspécifique. Vous voudrez bien citer toute variable contenant un nom de fichier, donc zip "${file%.*}.zip" "$file"avec les guillemets doubles autour des deux variables.
triple-
1
@ tripleee Tout d'abord, merci d'avoir signalé ma référence erronée à mkv. Deuxièmement, il est inutile de citer des arguments dans zsh, contrairement à dans bash. C'est pourquoi j'ai précisé qu'il s'agissait d'une commande zsh.
Radon Rosborough
Remplacer le dernier point-virgule par une esperluette pourrait l'accélérer considérablement (si le nombre de fichiers dans le répertoire est raisonnable ...). Sinon find . -type f -maxdepth 1 -print0|xargs -r0 -n1 -P64 -I{} bash -c 'f="{}"; zip "${f%.*}.zip" "$f"'(avec -Pajusté en fonction de vos threads CPU ...) (De nombreuses dépendances GNU ...)
Gert van den Berg
5

Une autre façon serait d'utiliser find et xargs: (cela pourrait inclure un répertoire "." Dans le zip, mais il devrait toujours être extrait correctement. Avec mon test, zip a supprimé le point avant la compression) find . -type f -exec zip zipfile.zip {} +

(Le +peut être remplacé par \;si votre version de findne supporte pas la +fin pour exec. Ce sera plus lent cependant ...)

Cela inclura par défaut tous les sous-répertoires. Trouver sur GNU -maxdepthpeut empêcher cela.

Gert van den Berg
la source
(contrairement aux solutions qui utilisent *, cela inclura les fichiers de points et ne tombera pas s'il y a trop de fichiers dans un répertoire)
Gert van den Berg
1

Une autre méthode (lente) pour faire cela (qui ajoute un fichier à la fois au zip):

for f in * .[^.]*; do
    [ -r "$f" ] || continue # Skip directories or non-existant files (Probably ".[^.]*" if directory has no dotfiles). Using -e will allow directories to be used as well
    zip zipfile.zip "$f" # If directories are included, you probably want to add -r
done

Cela a les problèmes de fichier de points de *(solution de contournement ajoutée) et serait démarrer zip une fois pour chaque fichier, en l'ajoutant à l'archive. Dans bash, il traiterait une grande quantité de fichiers.

Ce serait plus lent que la plupart des autres méthodes, mais c'est relativement simple.

Gert van den Berg
la source
1
Je dirais que c'est moins simple que la réponse acceptée et plus lent, ce qui soulève la question: "Pourquoi quelqu'un ferait-il cela?". Si vous pouvez répondre à cette question, je vous recommande de mettre ce contexte dans votre réponse, sinon je pense que c'est une mauvaise réponse à une vieille question qui a déjà une bonne réponse.
Centimane
@Centimane: Je note les limitations. Je pense que cela a une valeur éducative. (Si vous ne sautez pas de répertoires, c'est assez simple). Si vous voulez une réponse beaucoup plus rapide en utilisant un outil externe (standard), mon autre réponse couvre cela. (avec la manipulation des fichiers de points supprimée (ce qui affecte la correction sans leur absence mentionnée dans la question), je pense que c'est assez élégant):for f in *; do zip zip.zip "$f"; done
Gert van den Berg
1
Notez que la réponse acceptée n'utilise pas de commande externe et serait plus rapide. Dans quel scénario cette réponse serait-elle utile?
Centimane
@Centimane Avec tar quand il y a plus de fichiers que ce que bash peut passer en paramètre. (find + xargs sont meilleurs, car les boucles sont plus faciles ...). C'est une réponse (unique) à la question. Ce n'est certainement pas la réponse optimale. (Des réponses non optimales peuvent quand même être utiles pour des problèmes similaires, si quelqu'un se trouve dans une situation légèrement différente - par exemple, vouloir que tous les répertoires contenant un fichier tar soient enregistrés.)
Gert van den Berg