Comment “extraire” un fichier zip?

52

J'ai extrait un fichier zip dans un dossier non vide. Le fichier zip contient de nombreux fichiers et une hiérarchie profonde, qui ont fusionné avec l’arborescence existante du répertoire cible. Comment puis-je supprimer les fichiers et les répertoires qui ont été créés en décompressant sans détruire les fichiers et les répertoires déjà présents? Bien sûr, j'ai toujours le fichier zip que j'ai fusionné, donc les informations sont là.

mafp
la source
Merci pour l'acceptation, mais c'était vraiment l'idée de @ jjin. Je ne connaissais pas les lqoptions unzizp, j'ai juste ajouté quelques astuces classiques * nix autour de sa réponse principale.
Terdon
C'est bon, je m'en fiche un peu. J'ai ajouté ma propre version différente de la gestion des espaces blancs de toute façon.
Jjlin
@terdon Ouais ... J'ai voté la réponse de jjlin aussi, mais je ne peux accepter qu'une seule réponse.
mardi
Pour référence future, effectuez toujours l’une des opérations suivantes avec une archive inconnue, quel que soit son format: 1) Extrayez-le dans un répertoire vide ou 2) Répertoriez-le d’abord (unzip -l) avant de l’extraire pour que vous puissiez voir si c’est désagréable. Les archives faites sans répertoire de premier niveau avec tout ce qui se trouve en dessous sont de mauvaise forme. Lorsqu'elles ont fini avec du goudron, elles s'appellent en réalité des bombes à goudron, je suppose donc que cela pourrait s'appeler une bombe zip.
Joe
@ Joe Il a ses utilisations. Les packages LaTeX, par exemple, peuvent se présenter sous une foo.tds.zipforme. Ces zips se fondent dans un arbre TEXMF, ce qui est très pratique. Mais si vous souhaitez un jour supprimer un tel paquet, vous êtes confronté au problème que j'ai décrit.
mardi

Réponses:

28

La réponse de jjlin est la voie à suivre. Je veux juste ajouter quelques choix pour les répertoires:

  • Supprimer tous les fichiers extraits , pas de répertoires :

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done
    
  • Supprimer les fichiers extraits et les répertoires vides uniquement

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done; rmdir *
    

    En l'absence d'options, rmdirsupprime uniquement les répertoires vides, les fichiers et les dossiers non vides seront laissés de manière à pouvoir les exécuter en toute sécurité *.

  • Supprimer tout extrait, mais demander une confirmation avant chaque suppression:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -ri "$n"; done; rmdir *
    

    Le -idrapeau provoquera rmune invite avant chaque suppression, vous pouvez choisir Oui ou Non.

  • Supprimer tout extrait, répertoires inclus:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -rf "$n"; done
    
terdon
la source
La suppression de répertoires vides se fait facilement avec find: find * -depth -type d -exec rmdir {} +et ignorer tous les Directory not emptymessages. Il est peut-être légal de raccourcir cette étape find * -type d -deletecar l' -deleteoption est activée, -depthmais je n'ai pas vérifié que -deletecela ne supprimerait pas un répertoire non vide.
Adrian Pronk
@AdrianPronk ça ne marche pas:find: cannot delete './foo': Directory not empty
terdon
28

Vous pouvez utiliser unzip -lqq <filename.zip>pour lister le contenu du fichier zip; cela inclura toutefois des informations superflues que vous devrez filtrer. Voici une commande qui fonctionne pour moi:

unzip -lqq file.zip | awk '{print $4;}' | xargs rm -rf

La awkcommande extrait uniquement les noms des fichiers et des répertoires. Ensuite, le résultat est transmis à xargstout supprimer. Je suggère de commencer par exécuter une commande (en omettant la xargs rm -rfpartie) en premier pour vous assurer que les résultats sont corrects.

La commande ci-dessus aura des problèmes avec les chemins qui ont des espaces. Cette version (plus compliquée) devrait résoudre ce problème:

unzip -lqq file.zip | awk '{$1=$2=$3=""; sub(/ */, "", $0); printf "%s%s", $0, "\0"}' | xargs -0 rm -rf
jjlin
la source
Ceci est déjà assez proche de ce que j'avais en tête, mais unzip -lqqrépertorie également les répertoires contenus dans le zip. Pour le moment, je laisserais tous les répertoires en solitaire. Comment supprimer tous les répertoires vides d'une arborescence pourrait être une question complémentaire.
Mafp
@mafp C'est un bon point à propos des répertoires. Vous pouvez ajouter des éléments grep -v '/$'dans le pipeline pour ignorer la suppression des répertoires (qui ont tous une barre oblique finale, AFAICT).
Jjlin
@terdon En fait, je pense que le problème commence au début awk, car imprimer seulement 4 dollars n'imprimera pas le chemin complet.
Jjlin
Je ne pense pas que vous devriez utiliser l’ -roption de rm: cela semble poser problème, en particulier lorsque l’ -foption est combinée . Je n'utiliserais pas l' -foption du tout dans ce scénario.
Adrian Pronk
1
@jjlin: n'omettra grep -v '/$'que les entrées de répertoire dans le fichier ZIP. Ils incluront toujours des entrées qui étaient des fichiers simples dans le fichier ZIP mais qui étaient des répertoires préexistants dans le dossier cible. Pour cette raison, il serait sage d'omettre-r
Adrian Pronk le
11

Avec le commutateur -Z1, unzip listera exactement un fichier par ligne (et rien d’autre).

De cette façon, vous pouvez utiliser

unzip -Z1 | xargs -I {} rm '{}'

supprimer tous les fichiers extraits du fichier zip.

La commande

unzip -Z1 | xargs -I {} rm -rf '{}'

supprime également les répertoires, mais vous devez faire attention. Si les répertoires existaient déjà avant l'extraction du fichier zip, tous les fichiers préexistants de ces répertoires seront également supprimés.


Si vous voulez quand même ré-extraire le fichier zip, il existe une autre approche qui garantit de traiter les noms de fichiers étranges.

Commencez par extraire le fichier zip où vous vouliez l’extraire:

unzip file.zip -d elsewhere

Maintenant, allez dans le répertoire où vous avez extrait les fichiers par erreur et exécutez la commande suivante:

find elsewhere -type f -printf "%P\0" | xargs -0 -I {} rm '{}'
  • -type f ne trouve que des fichiers (pas de répertoires).

  • %P\0est le chemin relatif (sans elsewhere/), suivi d'un caractère nul.

  • -0fait que xargs sépare les lignes par des caractères nuls. Ceci est plus fiable car - en théorie - les noms de fichiers peuvent contenir des caractères de nouvelle ligne.


Pour gérer les répertoires restants, vous pouvez exécuter la commande:

find -type d -exec rmdir -p {} \; 2> /dev/null
  • -type d ne trouve que des répertoires.

  • -exec rmdir -p {} \;s’exécute rmdir -p {}pour chaque répertoire trouvé.

    {}est le répertoire qui a été trouvé et le -pcommutateur fait en sorte que rmdir supprime également ses répertoires parents vides.

  • 2> /dev/null supprime les messages d'erreur résultant de la tentative de suppression de répertoires non vides ou précédemment supprimés.


Pages de manuel connexes:

Dennis
la source
+1 pour m'avoir fait lire zipinfola page de manuel de.
Terdon
Eh bien, ça rend un peu plus facile. :)
jjlin
2

Voici une solution encore plus facile et plus sûre (je pense)

zip -m getmeoutofhere.zip `unzip -lqq myoriginalzipfile.zip`
rm getmeoutofhere.zip

Ce que cela fait: La commande unzip inversée produira une liste de ce qui était dans votre fichier d'origine.

zip -m utilisera ensuite cette liste pour ajouter add que chacun obtiendra getmeoutofhere.zip et le supprimera du répertoire d'origine (donc théoriquement, il devrait être indentif à myoriginalfile.zip.

L'inconvénient est que unzip -lqq produira du texte, des dates, des heures, une taille de fichier, etc. supplémentaires, ce qui obligera zip -m à produire des messages d'erreur, mais cela ne devrait pas avoir d'incidence (sauf si vous avez le cas improbable d'un fichier contenant le même fichier). Nom).

Veuillez noter que cela ne supprimera pas les répertoires créés lors de la décompression initiale.

David E.
la source
Approche intéressante, va explorer plus loin.
mardi
1

Si vous avez extrait les fichiers de telle sorte que l'horodatage de modification de l'archive ne soit pas conservé dans les copies extraites (mais que les fichiers extraits aient leur heure de modification habituelle), le bon moyen de l'attaquer est via l'heure de modification. Tous les fichiers extraits ont un horodatage de modification plus récent que le fichier existant le plus récemment modifié de ce répertoire.

Voici une situation simple.

Supposons qu'aucun des fichiers existants du répertoire en cours n'a été touché pendant au moins 24 heures. Tout ce qui a été modifié au cours des dernières 24 heures est donc indésirable à partir du fichier zip.

$ find . -mtime -1 -print0 | xargs -0 rm

Cela trouvera aussi certains répertoires, mais rmles laissera seuls. Ils peuvent être traités dans un second passage:

$ find . -mtime 1 -type d -print 0 | xargs -0 rmdir

Tous les répertoires récemment modifiés ont été modifiés par le zip. Si vous rmdirles supprimez avec succès, cela signifie qu'ils sont vides. Les répertoires vides qui ont été touchés par zip ont probablement été créés par celui-ci: c’est-à-dire issus de l’archive. Nous ne pouvons pas être sûrs à 100%. Il est possible que le travail de décompression mette certains fichiers dans un répertoire existant qui était vide.

Si findla granularité sur 24 heures ne convient pas au travail, car les fichiers de l’arborescence ont été modifiés trop récemment, je considérerai ensuite quelque chose de simple: supposons que le travail de décompression n’a placé aucun élément dans les sous-répertoires existants. C'est-à-dire que tout ce qui a été décompressé est soit un fichier au niveau supérieur, soit un nouveau sous-répertoire qui n'existait pas auparavant, qui ne contient donc que du matériel provenant du zip. Ensuite:

# list directory in descending order of modification time
$ ls -1t > filelist  # descending order of modification time

Nous ouvrons maintenant filelistun éditeur de texte et déterminons la première entrée de la liste qui ne provient pas du zip. Nous supprimons cette entrée et tout le reste après. Il ne reste que les fichiers et répertoires issus du zip. Premièrement, nous inspectons visuellement des problèmes tels que des espaces dans les noms et des occurrences de citations à échapper. Nous pouvons ensuite ajouter des guillemets autour de tout, si nécessaire: Ce qui suit suppose que vous utilisez Vim:

:%s/.*/"&"/

Puis joignez le tout dans une grande ligne:

:%j

Insérez maintenant rm -rfdevant:

Irm - rf<ESC>

Exécutez la ligne sous le curseur en tant que commande shell:

!!sh<Enter>

Je ne voudrais certainement pas automatiser les étapes de cette tâche, en raison du risque d'effacer des fichiers déjà présents ou de foirer en raison de problèmes de nom de fichier.

Si vous souhaitez obtenir une liste des chemins dans le fichier zip, capturez-le dans un fichier, examinez-le très attentivement et transformez-le en suppression après avoir effectué les modifications nécessaires.

Kaz
la source