Extrahieren verschachtelter ZIP-Dateien

15

Ich habe zahlreiche Zip-Archive, von denen jedes eine Reihe von Zip-Archiven enthält. Was ist der beste Weg, um alle in diesem Zip-Archiv und seinen untergeordneten Zip-Archiven enthaltenen Dateien, die selbst keine Zip-Archive sind, rekursiv zu extrahieren?

oadams
quelle
Was meinen Sie mit dem Extrahieren von Dingen, die keine ZIP-Dateien sind? Sie möchten sie an einen anderen Ort kopieren?
Phunehehe
Ich finde Ihre Anforderungen nicht klar. Ich finde Shawn J. Goff und meine Interpretation ungefähr gleich wahrscheinlich. Könnten Sie das klären?
Gilles SO - hör auf, böse
@Gilles: Entschuldigung, ja, es war ein bisschen unklar. Ich habe es ein wenig geändert, hoffentlich ist es jetzt klarer.
oadams
Ich wollte eine Antwort posten, aber ich bin der Meinung, dass dies als Kommentar gelten sollte: Verschachtelte Archive erhöhen den benötigten Speicherplatz! Du meinst wahrscheinlich das Zip-Dateiformat, nicht nur gzip. Jede zip-Datei ist bereits komprimiert und komprimiert sie erneut. Dadurch entsteht mehr Overhead, wodurch der benötigte Speicherplatz effektiv erhöht wird.
Polemon
Ja, ich habe es nicht getan: P. Leider bin ich dieser bizarren Art der Verteilung von Dateien ausgesetzt.
oadams

Antworten:

13

Dadurch werden alle Zip-Dateien in das aktuelle Verzeichnis extrahiert, mit Ausnahme der darin enthaltenen Zip-Dateien.

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

Obwohl hierdurch der Inhalt in das aktuelle Verzeichnis extrahiert wird, werden nicht alle Dateien ausschließlich in diesem Verzeichnis gespeichert, da der Inhalt möglicherweise Unterverzeichnisse enthält.

Wenn Sie eigentlich alle Dateien ausschließlich im aktuellen Verzeichnis haben wollen, können Sie ausführen

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

Hinweis: Dadurch werden Dateien gelöscht, wenn sich zwei Dateien mit demselben Namen in verschiedenen Verzeichnissen befinden.

Wenn Sie alle Zip-Dateien und die darin enthaltenen Reißverschlüsse rekursiv extrahieren möchten, werden im Folgenden alle Zip-Dateien im aktuellen Verzeichnis und alle darin enthaltenen Reißverschlüsse in das aktuelle Verzeichnis extrahiert.

while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
Shawn J. Goff
quelle
Diese while-Schleife hat mir sehr bei einem ethischen Hacking-Wettbewerb geholfen, bei dem eine verschachtelte Zip-Datei mit einer Tiefe von 31337 Ebenen erstellt wurde. Danke!
Peedee
2
Diese Variante, mit der ich Inhalte aus verschachtelten EAR-, WAR- und JAR-Dateien rekursiv extrahiere, könnte Ihnen gefallen: gist.github.com/tyrcho/479c18795d997c201e53 Der Hauptunterschied besteht darin, dass für jedes Archiv ein verschachtelter Ordner erstellt wird. while [ "finden . -type f -name '*.? 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

Soweit ich weiß, haben Sie Zip-Archive, die selbst Zip-Archive enthalten, und Sie möchten verschachtelte Zip-Archive jedes Mal entpacken, wenn eines extrahiert wird.

Hier ist ein Bash-4-Skript, das alle ZIP-Dateien im aktuellen Verzeichnis und seinen Unterverzeichnissen rekursiv dekomprimiert, jede ZIP-Datei nach dem Dekomprimieren entfernt und so lange weiterarbeitet, wie ZIP-Dateien vorhanden sind. Eine Zip-Datei in einem Unterverzeichnis wird relativ zu diesem Unterverzeichnis extrahiert. Warnung: Ungetestet: Erstellen Sie eine Sicherungskopie der Originaldateien, bevor Sie sie ausprobieren, oder rmverschieben Sie die ZIP-Datei aus dem Verzeichnisbaum .

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

Das Skript funktioniert auch in zsh, wenn Sie die shoptZeile durch ersetzen setopt nullglob.

Hier ist ein portables Äquivalent. Die Beendigungsbedingung ist etwas kompliziert, da findnicht spontan ein Status zurückgegeben wird, der angibt, ob Dateien gefunden wurden. Achtung: wie oben.

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 - hör auf böse zu sein'
quelle
1

unziptut dies nicht, weil der UNIX-Weg darin besteht, eine Sache zu tun und das gut zu machen, und nicht alle verrückten Sonderfälle in jedem Tool zu behandeln. Daher müssen Sie die Shell verwenden (die die Aufgabe erfüllt, Dinge gut zusammenzubinden). Dies macht es zu einer Programmierfrage, und da ALLE möglichen Programmierfragen in StackOverflow beantwortet wurden, hier: Wie entpacken Sie Archive in einem Verzeichnis und seinen Unterverzeichnissen rekursiv über die Unix-Befehlszeile?

Thomas Themel
quelle
1
Ich würde "using the shell" definitiv nicht als Programmierfrage bezeichnen, und "shell scripting" ist in den FAQ als Thema aufgeführt
Michael Mrozek
Ich wollte nicht implizieren, dass es hier überhaupt nicht zum Thema gehört, sondern nur begründen, warum es bei StackOverflow zum Thema gehört.
Thomas Themel
1

Dieses Perl-Skript extrahiert jede .zip-Datei in ein eigenes Unterverzeichnis. Führen Sie das Skript mehrmals aus, um verschachtelte ZIP-Dateien zu verarbeiten. ZIP-Dateien werden nach dem Extrahieren nicht gelöscht. Sie können diese Änderung jedoch vornehmen, indem Sie einen unlink () -Aufruf hinzufügen.

#!/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
quelle
1

Der einfachste Weg ist, atool zu verwenden: http://www.nongnu.org/atool/ Es ist ein sehr gutes Skript, das zip-, unzip-, tar-, rar-Programme usw. verwendet, um ein Archiv zu extrahieren.

Verwenden atool -x package_name.zipSie diese Option, um alle zu entpacken, oder verwenden Sie die einfache forSchleife, wenn Sie sie in einem Verzeichnis mit vielen Zip-Dateien verwenden möchten :

for f in *; do atool -x $f; fi(Sie müssen cdin das gewünschte Verzeichnis mit Zip-Dateien, bevor Sie dies verwenden).

Jeff Schaller
quelle
atoolDas Verhalten von unterscheidet sich hier nicht wesentlich von dem von unzip. Es extrahiert auch nicht rekursiv ZIP-Dateien.
Thomas Themel
@Thomas Themel: Sind Sie sicher, dass ZIP-Dateien nicht rekursiv extrahiert werden? Es kann aus deb-Dateien tar.gz rekursiv extrahieren, aber ich habe keine Zeit atm, um es mit verschachtelten zip-Archiven zu testen: \
0

Sie sollten vorsichtig sein, wenn Sie ZIP-Dateien innerhalb von ZIP-Dateien automatisch entpacken:

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

Es ist möglich, eine Zip-Datei zu erstellen, die eine Zip-Datei als Ausgabe erzeugt, die eine Zip-Datei als Ausgabe erzeugt usw. usw. Das heißt, Sie können eine Zip-Datei erstellen, die ein fester Bestandteil des Programms zum "Entpacken" ist.

Außerdem erinnere ich mich an Leute, die Zip-Dateien erstellt haben, die "explodieren" würden. Dies ist eine sehr kleine Zip-Datei, die auf mehrere Gigabyte entpackt wird. Dies ist eine Facette der Komprimierungsmethode.

Bruce Ediger
quelle
0

Vielleicht hilft das (hat bei mir funktioniert):

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
quelle
0

Ich brauchte eine Lösung wie die von Giles aus dem Jahr 2010, außer dass ich die Ordnerstruktur beibehalten und nicht alles in das oberste Verzeichnis entpacken musste. Hier ist meine Einstellung zu seiner mit drei hinzugefügten / geänderten Zeilen:

#!/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
Steakchips
quelle
0

Kasse dieses Java-basierten Dienstprogramms nzip für verschachtelte zip-Dateien. Das Extrahieren und Komprimieren verschachtelter Reißverschlüsse ist mit den folgenden Befehlen ganz einfach

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

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

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

PS. Ich bin der Autor und werde gerne alle Fehler schnell beheben.

user930412
quelle