2008-09-20 14 views
43

Der Befehl unzip verfügt nicht über eine Option zum rekursiven Entpacken von Archiven.Wie dekomprimieren Sie rekursiv Archive in einem Verzeichnis und seinen Unterverzeichnissen aus der Unix-Befehlszeile?

Wenn ich die folgende Verzeichnisstruktur und Archive:

 
/Mother/Loving.zip 
/Scurvy/Sea Dogs.zip 
/Scurvy/Cures/Limes.zip 

Und ich möchte alle die Archive in Verzeichnisse mit dem gleichen Namen wie jedes Archiv entpacken:

 
/Mother/Loving/1.txt 
/Mother/Loving.zip 
/Scurvy/Sea Dogs/2.txt 
/Scurvy/Sea Dogs.zip 
/Scurvy/Cures/Limes/3.txt 
/Scurvy/Cures/Limes.zip 

Welcher Befehl oder Befehle würde ich ausgeben?

Es ist wichtig, dass dies nicht auf Dateinamen mit Leerzeichen in ihnen erstickt.

+0

Wie wäre es mit langen Dateipfaden ... mehr als 260 Zeichen ...: https://superuser.com/a/1263234/439537 – Andrew

Antwort

59

Wenn Sie die Dateien in den entsprechenden Ordner extrahieren möchten, können Sie versuchen, diese

find . -name "*.zip" | while read filename; do unzip -o -d "`dirname "$filename"`" "$filename"; done; 

Ein Mehr verarbeitete Version für Systeme, die eine hohe I/O verarbeiten kann:

find . -name "*.zip" | xargs -P 5 -I fileName sh -c 'unzip -o -d "$(dirname "fileName")/$(basename -s .zip "fileName")" "fileName"' 
+1

Dies ist die richtige Vorgehensweise, da das vollständige Verzeichnis beibehalten wird Struktur! – kynan

+2

__NOTE__ - dies extrahiert nicht die Dateien in Verzeichnisse mit dem gleichen Namen wie das Archiv, wie angefordert. – emlai

+0

Ich hatte keine Ahnung XARGS hat Multi-Core-Unterstützung! – chuckrector

29

Hier ist eine Lösung, die den Befehl find und eine while-Schleife beinhaltet:

find . -name "*.zip" | while read filename; do unzip -o -d "`basename -s .zip "$filename"`" "$filename"; done; 
+3

** HINWEIS ** - dies extrahieren alle Zip-Dateien in das ** Arbeitsverzeichnis ! ** während Sie eine relative Entpackung angefordert haben. siehe [Viveks Antwort] (http://stackoverflow.com/a/2318189/3191896) –

+0

Hmm, es scheint nicht so, als ob sie alle in das Arbeitsverzeichnis AFAICT extrahiert würden. Ich benutze UnZip 5.52 von OS X El Capitan 10.11.6. Die Ergebnisse scheinen mit denen von Vivek identisch zu sein. Akzeptiert seine Antwort, da es auch zeigt, wie man mehrere Kerne nutzen kann! – chuckrector

2

So etwas wie gunzip die -r Flag verwendet ....

Travel die Verzeichnisstruktur rekursiv?. Wenn einer der in der Kommandozeile angegebenen Dateinamen Verzeichnisse sind, steigt gzip in das Verzeichnis ein und komprimiert alle dort gefundenen Dateien (oder entpackt sie im Fall von gunzip).

http://www.computerhope.com/unix/gzip.htm

+2

Er spricht speziell über Zip-Dateien, nicht über Gzip-Dateien. – dvorak

4

Sie mit dem exec-Flag findet zusammen in einer einzigen Befehlszeile verwenden könnte zu tun, ist die Aufgabe

find . -name "*.zip" -exec unzip {} \; 
+0

Dies entpackt alles in das aktuelle Verzeichnis und nicht relativ zu jedem Unterverzeichnis. Es wird auch nicht in ein Verzeichnis mit demselben Namen wie jedes Archiv entpackt. – chuckrector

+0

Ich gehe davon aus, dass das Recht -d als Übung für den Leser belassen wird. Dieser Leser muss beachten, dass -exec nur eine Verwendung von {} im Befehl erlaubt - umgehen Sie dies, indem Sie sh aufrufen und {} einer Variablen zuweisen. –

+0

Beachten Sie auch, dass -execdir manchmal -exec vorzuziehen ist. In diesem Fall glaube ich nicht, dass es eine Rolle spielt. –

0

Wenn Sie mit Cygwin, die Syntax etwas anders für die Basisnamen Befehl.

find . -name "*.zip" | while read filename; do unzip -o -d "`basename "$filename" .zip`" "$filename"; done; 
0

Mir ist klar, dass das sehr alt ist, aber es war einer der ersten Hits bei Google, als ich nach einer Lösung für etwas Ähnliches suchte, also poste ich, was ich hier gemacht habe. Mein Szenario ist etwas anders als ich im Grunde wollte nur voll ein Glas zu explodieren, zusammen mit allen Gläsern in ihr enthalten, also schrieb ich folgende bash Funktionen:

function explode { 
    local target="$1" 
    echo "Exploding $target." 
    if [ -f "$target" ] ; then 
     explodeFile "$target" 
    elif [ -d "$target" ] ; then 
     while [ "$(find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)")" != "" ] ; do 
      find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)" -exec bash -c 'source "<file-where-this-function-is-stored>" ; explode "{}"' \; 
     done 
    else 
     echo "Could not find $target." 
    fi 
} 

function explodeFile { 
    local target="$1" 
    echo "Exploding file $target." 
    mv "$target" "$target.tmp" 
    unzip -q "$target.tmp" -d "$target" 
    rm "$target.tmp" 
} 

Hinweis der <file-where-this-function-is-stored>, die benötigt wird, wenn Sie speichern dies in einer Datei, die nicht für eine nicht interaktive Shell gelesen wird, wie ich es gerade war. Wenn Sie die Funktionen in einer Datei speichern, die auf nicht interaktiven Shells geladen ist (z. B. .bashrc, glaube ich), können Sie die gesamte source-Anweisung löschen. Hoffentlich wird das jemandem helfen.

Eine kleine Warnung - explodeFile löscht auch die ziped Datei, Sie können das natürlich ändern, indem Sie die letzte Zeile auskommentieren.

10

Eine Lösung, die alle Dateinamen (einschließlich Zeilenumbrüche) korrekt behandelt und extrahiert in ein Verzeichnis, das als Datei an derselben Stelle ist, nur mit der Erweiterung entfernt:

find . -name '*.zip' -exec sh -c 'unzip -o -d "${0%.*}" "$0"' '{}' ';' 

Beachten Sie, dass Sie leicht machen können es mehr Dateitypen (wie .jar) behandeln sie durch Zugabe mit -o, zB:

find . '(' -name '*.zip' -o -name '*.jar' ')' -exec ... 
0

Eine weitere interessante Lösung wäre:

DESTINY=[Give the output that you intend] 

# Don't forget to change from .ZIP to .zip. 
# In my case the files were in .ZIP. 
# The echo were for debug purpose. 

find . -name "*.ZIP" | while read filename; do 
ADDRESS=$filename 
#echo "Address: $ADDRESS" 
BASENAME=`basename $filename .ZIP` 
#echo "Basename: $BASENAME" 
unzip -d "$DESTINY$BASENAME" "$ADDRESS"; 
done;