Comment compresser plusieurs fichiers en ligne de commande?

16

Pardonnez cette question la plus élémentaire, mais je n'ai pas pu trouver de réponse directe ou d'exemple simple sur l'échange de pile.

Disons que j'ai un dossier de fichiers que je voudrais compresser en un seul fichier zip que je peux partager avec mes terribles amis Windows (sinon je l'utiliserais taret j'en aurais fini). Cela ressemble à ceci:

.
├── file1.txt
├── file2.txt
├── file3.txt
├── file.jpg
└── test.jpg

En supposant que j'ai zipinstallé:

sudo apt-get install zip

Je vois man zipque cela me permet d'utiliser une liste de fichiers:

- @ listes de fichiers. Si une liste de fichiers est spécifiée comme - @ [Pas sous MacOS], zip prend la liste des fichiers d'entrée à partir de l'entrée standard au lieu de la ligne de commande. Par exemple,

          zip -@ foo

J'ai donc créé zip.lstce qui ressemble à ceci:

cat zip.lst

file1.txt
file2.txt
file3.txt
file.jpg
test.jpg

Et maintenant j'ai essayé:

zip -@ zip.lst

Mais cela n'a rien fait d'autre que de créer une ligne vierge sur la console. Et je peux continuer à pousser Enteret ça continue de faire plus de lignes vides sans exécuter apparemment la commande. Après quelques recherches, j'ai réalisé que je devais terminer la saisie en appuyant sur Ctrl+D

Mais maintenant, je reçois cette erreur:

    zip warning: missing end signature--probably not a zip file (did you
    zip warning: remember to use binary mode when you transferred it?)
    zip warning: (if you are trying to read a damaged archive try -F)

zip error: Zip file structure invalid (zip.lst)

Quoi!? Comment ma simple liste n'est-elle pas une "structure de fichier valide"? Retour au manuel pour plus d'informations, et je regarde de plus près:

Si une liste de fichiers est spécifiée comme - @ ...

Je l'essaie donc sans -@, et cela au moins le traite tout de suite sans avoir à appuyer sur Ctrl+ Dmais je reste avec la même erreur .

Heureusement, j'ai trouvé un commentaire sur une réponse à une question presque sans rapport qui m'a amené à réaliser que je devais nommer explicitement le fichier zip. Cette erreur est due au fait que par défaut, il essayait de créer un fichier zip appelé zip.lst. Mais comme c'est le nom de ma liste, on pourrait penser qu'elle la remplacerait simplement, mais non, elle essayait en fait de la mettre à jour. Et puisque la liste n'est évidemment pas un fichier zip, nous obtenons l'erreur de structure de fichier invalide, et maintenant il est clair pourquoi il a dit "probablement pas un fichier zip." Alors j'ai essayé:

zip files.zip zip.lst

adding: zip.lst (deflated 35%)

Eureka! Je peux voir que le fichier zip a été créé et mon dossier contient maintenant ceci:

.
├── file1.txt
├── file2.txt
├── file3.txt
├── file.jpg
├── files.zip
├── test.jpg
└── zip.lst

Mais attendez avant de célébrer, confirmons d'abord le contenu du fichier zip:

unzip -l files.zip

Archive:  files.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       48  2016-05-24 15:30   zip.lst
---------                     -------
       48                     1 file

Non! Eh bien, en fait, cela a du sens par rapport à l'utilisation standard, car il vient de compresser le fichier de liste que je lui ai donné. Finalement j'ai réessayé avec -@mais j'ai obtenu le même résultat.

Qu'est-ce que je fais mal?

BTW, je sais que je peux utiliser l'interface graphique et le faire avec ma souris, mais j'ai besoin de script cela, et en général je suis plus rapide sur la CLI quand je sais ce que je fais.

Jeff Puckett
la source

Réponses:

23

Utiliser la <redirection de fichiers

zip files.zip -@ < zip.lst

Ou vous pouvez sauter la liste et simplement glob

zip files.zip *.txt *.jpg

merci steeldriver

Réponse historique

Je suis content que ce soit OK de répondre à ma propre question parce que je voulais faire la chronique de mes turbulences dans l'espoir que d'autres qui suivent derrière moi dans ma traînée de larmes pourraient être épargnés en cherchant quelques mots clés.

Finalement, j'ai découvert la bonne réponse , mais elle a été envoyée à la mauvaise question .

Quelques points de clarté:

  • Le manuel ne fait pas référence à une liste littérale comme dans un fichier, mais plutôt à la liste des fichiers sur la console.
  • Il est compréhensible que quelqu'un puisse être induit en erreur en pensant fooà la liste de fichiers, mais il est en fait destiné à représenter le nom du fichier zip de sortie.
  • La liste des fichiers est omise dans l'exemple car il utilise le -@commutateur, ce qui démontre qu'il "prend la liste des fichiers d'entrée à partir de l'entrée standard au lieu de la ligne de commande "

Comprenant cela, nous sommes maintenant armés de diverses façons d'atteindre l'objectif.

Tout d'abord en utilisant la liste de fichiers que nous avons créée, nous pouvons lire la liste avec catet rediriger la sortie avec un tube comme entrée standard vers zip:

cat zip.lst | zip -@ files.zip

  adding: file1.txt (stored 0%)
  adding: file2.txt (stored 0%)
  adding: file3.txt (stored 0%)
  adding: file.jpg (stored 0%)
  adding: test.jpg (stored 0%)

Voir cela adding: ...pour chaque fichier est certainement un bon signe, mais nous avions déjà espéré, alors confirmons simplement:

unzip -l files.zip

Archive:  files.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2016-05-24 14:54   file1.txt
        0  2016-05-24 14:54   file2.txt
        0  2016-05-24 14:54   file3.txt
        0  2016-05-24 15:00   file.jpg
        0  2016-05-24 14:59   test.jpg
---------                     -------
        0                     5 files

SUCRÉ! Mais qui veut quand même créer une liste à usage unique? C'est une terrible façon détournée de résoudre ce scénario particulier. Il serait préférable d'obtenir une liste lset de la canaliser pour compresser:

ls | zip -@ files.zip

  adding: file1.txt (stored 0%)
  adding: file2.txt (stored 0%)
  adding: file3.txt (stored 0%)
  adding: file.jpg (stored 0%)
  adding: test.jpg (stored 0%)

Fabuleux! Créons maintenant des filtres avec la puissance impressionnante de grepsimplement compresser les jpg par exemple:

ls | grep .jpg | zip -@ images.zip

  adding: file.jpg (stored 0%)
  adding: test.jpg (stored 0%)

Ou tout simplement des fichiers commençant par "fichier"

ls | grep file. | zip -@ files.zip

  adding: file1.txt (stored 0%)
  adding: file2.txt (stored 0%)
  adding: file3.txt (stored 0%)
  adding: file.jpg (stored 0%)
Jeff Puckett
la source
5
Au lieu d'utiliser lset grepet zip -@, vous pouvez utiliser des globes shell pour sélectionner des fichiers directement sur la ligne de commande zip, par exemple zip files.zip file*ou zip images.zip *.jpg. De plus, lorsque vous utilisez une liste de noms de fichiers à partir d'un fichier, vous pouvez utiliser la redirection au lieu d'invoquer un processus cat distinct,zip files.zip -@ < zip.lst
steeldriver
Comment pouvez-vous faire fonctionner cela avec des répertoires imbriqués aux côtés de fichiers?
BallpointBen
@BallpointBen que j'utiliserais findau lieu dels
Jeff Puckett
6

la commande la plus simple avec un niveau de compression maximum

zip -9 -r filename.zip /path/to/dir singlefile.jpg 
Ansyori
la source