Extraer archivos zip anidados

15

Tengo numerosos archivos zip, cada uno de los cuales contiene varios archivos zip. ¿Cuál es la mejor manera de extraer recursivamente todos los archivos contenidos en este archivo zip y sus archivos zip secundarios, que no son archivos zip en sí mismos?

oadams
fuente
¿Qué quieres decir con extraer cosas que no son archivos zip? quieres copiarlos a otro lugar?
phunehehe
No encuentro sus requisitos claros. Encuentro que Shawn J. Goff y mi interpretación son igualmente probables. ¿Podrías aclarar?
Gilles 'SO- deja de ser malvado'
@Gilles: Lo siento, sí, no estaba claro. Lo cambié un poco, espero que ahora esté más claro.
Oadams
Iba a publicar una respuesta, pero creo que debería ir como un comentario: ¡Los archivos anidados aumentan el espacio que necesitas! Probablemente se refiera al formato de archivo Zip, no solo a gzip. cada archivo zip ya está comprimido, comprimiéndolos nuevamente, solo crea más sobrecarga, aumentando efectivamente el espacio necesario.
polemon
Sí, no lo hice: P. Lamentablemente, estoy sujeto a esta extraña forma de distribuir archivos.
oadams

Respuestas:

13

Esto extraerá todos los archivos zip en el directorio actual, excluyendo cualquier archivo zip que contenga.

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

Aunque esto extrae el contenido al directorio actual, no todos los archivos terminarán estrictamente en este directorio ya que el contenido puede incluir subdirectorios.

Si realmente quería todos los archivos estrictamente en el directorio actual, puede ejecutar

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

Nota: esto bloqueará los archivos si hay dos con el mismo nombre en diferentes directorios.

Si desea extraer recursivamente todos los archivos zip y las cremalleras que contiene, a continuación se extraen todos los archivos zip en el directorio actual y todas las cremalleras contenidas en ellos al directorio actual.

while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
Shawn J. Goff
fuente
este bucle while me ayudó mucho en una competencia de piratería ética donde habían preparado un archivo zip anidado con 31337 niveles de profundidad, ¡gracias!
peedee
2
Puede que le guste esta variante que uso para extraer recursivamente contenidos de archivos anidados de oído, guerra y jar: gist.github.com/tyrcho/479c18795d997c201e53 La principal diferencia es que crea una carpeta anidada para cada archivo. while [ "encontrar . -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

Según tengo entendido, usted tiene archivos zip que contienen archivos zip, y le gustaría descomprimir los archivos comprimidos anidados cada vez que se extrae uno.

Aquí hay un script bash 4 que descomprime todas las cremalleras en el directorio actual y sus subdirectorios de forma recursiva, elimina cada archivo zip después de que se ha descomprimido y continúa mientras existan archivos zip. Se extrae un archivo zip en un subdirectorio en relación con ese subdirectorio. Advertencia: sin probar, haga una copia de seguridad de los archivos originales antes de probarlo o reemplácelo rmmoviendo el archivo zip fuera del árbol de directorios .

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

El script también funcionará en zsh si reemplaza la shoptlínea con setopt nullglob.

Aquí hay un equivalente portátil. La condición de terminación es un poco complicada porque findno devuelve espontáneamente un estado para indicar si ha encontrado algún archivo. Advertencia: como arriba.

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- deja de ser malvado'
fuente
1

unzipno hace esto, porque la forma UNIX es hacer una cosa y hacerlo bien, no manejar todos los casos especiales locos en cada herramienta. Por lo tanto, debe usar el shell (que hace bien el trabajo de "unir las cosas"). Esto lo convierte en una pregunta de programación, y dado que TODAS las posibles preguntas de programación han sido respondidas en StackOverflow, aquí: ¿Cómo descomprime recursivamente archivos en un directorio y sus subdirectorios desde la línea de comandos de Unix?

Thomas Themel
fuente
1
Definitivamente no llamaría "usar el shell" una pregunta de programación, y el "script de shell" aparece en las preguntas frecuentes como sobre el tema
Michael Mrozek
No tenía la intención de dar a entender que estaba fuera de tema aquí en absoluto, solo quería justificar por qué está en el tema en StackOverflow.
Thomas Themel
1

Este script perl extraerá cada archivo .zip en su propio subdirectorio. Ejecute el script más de una vez para manejar archivos zip anidados. No elimina los archivos .zip después de la extracción, pero puede hacer ese cambio agregando una llamada 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
fuente
1

La forma más fácil es usar atool: http://www.nongnu.org/atool/ Es un script muy bueno que usa programas zip, unzip, tar, rar, etc. para extraer cualquier archivo.

Use atool -x package_name.zippara descomprimirlos a todos o si desea usarlo en el directorio con muchos archivos zip, use un forbucle simple :

for f in *; do atool -x $f; fi(deberá cdingresar al directorio deseado con los archivos zip antes de usar esto).

Jeff Schaller
fuente
atoolEl comportamiento aquí no difiere significativamente de descomprimir, diría, tampoco extrae archivos ZIP de forma recursiva.
Thomas Themel
@ Thomas Themel: ¿Estás seguro de que no extrae archivos ZIP de forma recursiva? Puede extraerse de los archivos deb tar.gz de forma recurrente pero no tengo cajero automático para probarlo con archivos zip anidados: \
0

Deberá tener cuidado al descomprimir automáticamente los archivos zip dentro de los archivos zip:

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

Es posible inventar un archivo zip que produzca un archivo zip como salida, lo que produce un archivo zip como salida, etc.

Además, me parece recordar que las personas que crean archivos zip que "explotarían", es decir, un archivo zip muy pequeño se descomprimiría en varios gigabytes de salida. Esta es una faceta del método de compresión.

Bruce Ediger
fuente
0

Quizás esto ayude (funcionó para mí):

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

}
usuario151061
fuente
0

Necesitaba una solución como la de Giles de 2010, excepto que necesitaba preservar la estructura de la carpeta, no descomprimir todo en el directorio de nivel superior. Aquí está mi opinión sobre la suya con tres líneas agregadas / modificadas:

#!/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
chips de carne
fuente
0

Echa un vistazo a esta utilidad nzip basada en Java para archivos zip anidados. La extracción y compresión de las cremalleras anidadas se puede hacer fácilmente usando los siguientes comandos

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"

PD. Soy el autor y estaré encantado de corregir cualquier error rápidamente.

usuario930412
fuente