Extraire des fichiers zip imbriqués

15

J'ai de nombreuses archives zip, chacune contenant un certain nombre d'archives zip. Quelle est la meilleure façon d'extraire récursivement tous les fichiers contenus dans cette archive zip et ses archives zip enfant, qui ne sont pas des archives zip elles-mêmes?

oadams
la source
que voulez-vous dire par extraire des choses qui ne sont pas des fichiers zip? vous voulez les copier dans un autre endroit?
phunehehe
Je ne trouve pas vos exigences claires. Je trouve que Shawn J. Goff et mon interprétation sont tout aussi probables. Pourriez-vous clarifier?
Gilles 'SO- arrête d'être méchant'
@ Gilles: Désolé, oui, c'était un peu flou. Je l'ai un peu changé, j'espère que c'est plus clair maintenant.
oadams
J'allais poster une réponse, mais je pense que cela devrait aller comme un commentaire: les archives imbriquées augmentent l'espace dont vous avez besoin! Vous voulez probablement dire le format de fichier Zip, pas seulement gzip. chaque fichier zip est déjà compressé, les compressant à nouveau, crée simplement plus de surcharge, augmentant efficacement l'espace nécessaire.
polemon
Ouais, je ne l'ai pas fait: P. Malheureusement, je suis soumis à cette façon bizarre de distribuer des fichiers.
oadams

Réponses:

13

Cela extraira tous les fichiers zip dans le répertoire courant, à l'exception de tous les fichiers zip qu'ils contiennent.

find . -type f -name '*.zip' -exec unzip -- '{}' -x '*.zip' \;

Bien que cela extrait le contenu du répertoire en cours, tous les fichiers ne se retrouveront pas strictement dans ce répertoire car le contenu peut inclure des sous-répertoires.

Si vous vouliez réellement tous les fichiers strictement dans le répertoire courant, vous pouvez exécuter

find . -type f -mindepth 2 -exec mv -- '{}' . \;

Remarque: cela encombrera les fichiers s'il y en a deux avec le même nom dans des répertoires différents.

Si vous souhaitez extraire récursivement tous les fichiers zip et les zips qu'ils contiennent, ce qui suit extrait tous les fichiers zip du répertoire en cours et tous les zips qu'ils contiennent dans le répertoire en cours.

while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
Shawn J. Goff
la source
cette boucle while m'a beaucoup aidé dans un concours de piratage éthique où ils avaient préparé un fichier zip imbriqué avec une profondeur de 31337 niveaux, merci!
peedee
2
vous aimerez peut-être cette variante que j'utilise pour extraire récursivement le contenu des fichiers emboîtés, war, jar: gist.github.com/tyrcho/479c18795d997c201e53 La principale différence est qu'il crée un dossier imbriqué pour chaque archive. while [ "trouver . -type f -nom '*.? ar' | wc -l" -gt 0 ]; do find -type f -name "*.?ar" -exec mkdir -p '{}.dir' \; -exec unzip -d '{}.dir' -- '../{}' \; -exec rm -- '{}' \;; done
Michel Daviot
4

Pour autant que je sache, vous avez des archives zip qui elles-mêmes contiennent des archives zip, et vous souhaitez décompresser les zips imbriqués chaque fois qu’une est extraite.

Voici un script bash 4 qui décompresse tous les zips du répertoire actuel et de ses sous-répertoires de manière récursive, supprime chaque fichier zip après qu'il a été décompressé et continue tant qu'il y a des fichiers zip. Un fichier zip dans un sous-répertoire est extrait par rapport à ce sous-répertoire. Attention: non testé, faites une sauvegarde des fichiers originaux avant de l'essayer ou remplacez-le rmen déplaçant le fichier zip en dehors de l'arborescence des répertoires .

shopt -s globstar nullglob
while set -- **/*.zip; [ $# -ge 1 ] do
  for z; do
    ( cd -- "$(dirname "$z")" &&
      z=${z##*/} &&
      unzip -- "$z" &&
      rm -- "$z"
    )
  done
done

Le script fonctionnera également dans zsh si vous remplacez la shoptligne par setopt nullglob.

Voici un équivalent portable. La condition de terminaison est un peu compliquée car findne renvoie pas spontanément un statut pour indiquer s'il a trouvé des fichiers. Avertissement: comme ci-dessus.

while [ -n "$(find . -type f -name '*.zip' -exec sh -c '
    cd "${z%/*}" &&
    z=${z##*/} &&
    unzip -- "$z" 1>&2 &&
    rm -- "$z" &&
    echo 1
')" ]; do :; done
Gilles 'SO- arrête d'être méchant'
la source
1

unzipne le fait pas, car la manière UNIX est de faire une chose et de bien le faire, de ne pas gérer tous les cas spéciaux fous dans chaque outil. Ainsi, vous devez utiliser le shell (qui fait bien le travail de "lier les choses"). Cela en fait une question de programmation, et puisque TOUTES les questions de programmation possibles ont été résolues sur StackOverflow, ici: Comment décompressez-vous récursivement des archives dans un répertoire et ses sous-répertoires à partir de la ligne de commande Unix?

Thomas Themel
la source
1
Je n'appellerais certainement pas "utilisation du shell" une question de programmation, et "script shell" est répertorié dans la FAQ comme sujet
Michael Mrozek
Je ne voulais pas laisser entendre que c'était hors sujet ici, je voulais juste justifier pourquoi c'est sur le sujet chez StackOverflow.
Thomas Themel
1

Ce script perl extraira chaque fichier .zip dans son propre sous-répertoire. Exécutez le script plusieurs fois pour gérer les fichiers zip imbriqués. Il ne supprime pas les fichiers .zip après l'extraction, mais vous pouvez apporter cette modification en ajoutant un appel unlink ().

#!/usr/bin/perl -w

# This script unzips all .zip files it finds in the current directory
# and all subdirectories.  Contents are extracted into a subdirectory
# named after the zip file (eg. a.zip is extracted into a/).
# Run the script multiple times until all nested zip files are
# extracted.  This is public domain software.

use strict;
use Cwd;

sub process_zip {
    my $file = shift || die;
    (my $dir = $file) =~ s,/[^/]+$,,;
    (my $bare_file = $file);
    $bare_file =~ s,.*/,,;
    my $file_nopath = $bare_file;
    $bare_file =~ s,\.zip$,,;
    my $old_dir = getcwd();
    chdir($dir) or die "Could not chdir from '$old_dir' to '$dir': $!";
    if (-d $bare_file) {
        chdir($old_dir);
        # assume zip already extracted
        return;
    }
    mkdir($bare_file);
    chdir($bare_file);
    system("unzip '../$file_nopath'");
    chdir($old_dir);
}

my $cmd = "find . -name '*.zip'";
open(my $fh, "$cmd |") or die "Error running '$cmd': $!";
while(<$fh>) {
    chomp;
    process_zip($_);
}
John
la source
1

La manière la plus simple est d'utiliser atool: http://www.nongnu.org/atool/ C'est un très bon script qui utilise des programmes zip, unzip, tar, rar etc. pour extraire n'importe quelle archive.

Utilisez-les atool -x package_name.zippour tous les décompresser ou si vous souhaitez les utiliser dans un répertoire contenant de nombreux fichiers zip, utilisez une forboucle simple :

for f in *; do atool -x $f; fi(vous devrez cddans le répertoire souhaité avec des fichiers zip avant de l'utiliser).

Jeff Schaller
la source
atoolLe comportement de ici ne diffère pas significativement de la décompression je dirais, il n'extrait pas récursivement les fichiers ZIP non plus.
Thomas Themel
@Thomas Themel: Êtes-vous sûr qu'il n'extrait pas récursivement les fichiers ZIP? Il peut extraire des fichiers deb tar.gz de manière récurrente mais je n'ai pas le temps de le tester avec des archives zip imbriquées: \
0

Vous devrez être prudent en décompressant automatiquement les fichiers zip à l'intérieur des fichiers zip:

http://research.swtch.com/2010/03/zip-files-all-way-down.html

Il est possible de concocter un fichier zip qui produit un fichier zip en sortie, qui produit un fichier zip en sortie, etc etc etc. Autrement dit, vous pouvez créer un fichier zip qui est une once fixe de "décompresser" le programme.

De plus, il me semble que les gens fabriquent des fichiers zip qui "explosent", c'est-à-dire qu'un très petit fichier zip se décompresse en plusieurs gigaoctets de sortie. Il s'agit d'une facette de la méthode de compression.

Bruce Ediger
la source
0

Peut-être que cela aidera (a fonctionné pour moi):

function unzipAll(){

# find and count archives
archLst=`find . -type f -name "*.*ar"`
archLstSize=`echo $archLst| awk 'END{print NF}'`

# while archives exists do extract loop
while [ "$archLstSize" -gt 0 ]; do

# extract and remove all archives (found on single iteration)
for x in $archLst; do 
mv "${x}" "${x}_";
unzip "${x}_" -d "${x}" && rm "${x}_"; 
done; #EO for

# find and count archives
archLst=`find . -type f -name "*.*ar"`
archLstSize=`echo $archLst| awk 'END{print NF}'`

done #EO while

}
user151061
la source
0

J'avais besoin d'une solution comme celle de Giles à partir de 2010, sauf que j'avais besoin de préserver la structure des dossiers, de ne pas tout décompresser dans le répertoire de niveau supérieur. Voici mon point de vue sur le sien avec trois lignes ajoutées / modifiées:

#!/bin/bash
shopt -s globstar nullglob
while set -- **/*.zip; [ $# -ge 1 ]
do
    for z
    do
        ( cd -- "$(dirname "$z")" &&
            z=${z##*/} &&
            cp -- "$z" "$z".bak &&
            mkdir -- "$z"dir &&
            unzip -- "$z" -d "$z"dir &&
            rm -- "$z"
        )
    done
done
steaknchips
la source
0

Découvrez cet utilitaire nzip basé sur java pour les fichiers zip imbriqués. L'extraction et la compression de zips imbriqués peuvent être effectuées facilement à l'aide des commandes suivantes

java -jar nzip.jar -c list -s readme.zip

java -jar nzip.jar -c extract -s "C: \ project \ readme.zip" -t readme

java -jar nzip.jar -c compress -s readme -t "C: \ project \ readme.zip"

PS. Je suis l'auteur et serai heureux de corriger rapidement tout bogue.

user930412
la source