2008-09-20 16 views
43

El comando unzip no tiene una opción para descomprimir archivos de manera recursiva.¿Cómo descomprime archivos de manera recursiva en un directorio y sus subdirectorios desde la línea de comandos de Unix?

Si tienen la siguiente estructura de directorios y archivos:

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

Y quiero descomprimir todos los archivos en directorios con el mismo nombre que cada archivo comprimido:

 
/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 

¿Qué comando o ¿Comandos debería emitir?

Es importante que esto no ahogue en los nombres de archivos que tienen espacios en ellos.

+0

¿Qué hay de archivos largos caminos ... más allá de los 260 caracteres ...: https://superuser.com/a/1263234/439537 – Andrew

Respuesta

59

Si desea extraer los archivos en la carpeta respectiva puede probar esta

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

Una versión multi-procesado de sistemas que puedan manejar alta de E/S:

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

Esta es la forma correcta de hacerlo, ya que conserva el directorio completo ! – kynan

+2

estructura __NOTE__ - esto no extraer los archivos en directorios con el mismo nombre que el archivo, conforme a lo solicitado – emlai

+0

no tenía idea xargs tiene soporte multi-núcleo – chuckrector

29

Aquí hay una solución que implique el comando find y un bucle while:

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

** NOTA ** - Este extracto de todos los archivos zip en el directorio de trabajo ** ! ** mientras solicitaba una descompresión relativa. ver [respuesta de Vivek] (http://stackoverflow.com/a/2318189/3191896) –

+0

Hmm, no parece extraerlos todos al directorio de trabajo AFAICT. Estoy usando UnZip 5.52 de OS X El Capitan 10.11.6. Los resultados parecen ser idénticos a los de Vivek. Aceptando su respuesta, ¡ya que también muestra cómo aprovechar múltiples núcleos! – chuckrector

2

Algo así como gunzip usando el indicador -r ....

viaje la estructura de directorios de forma recursiva?. Si alguno de los nombres de archivo especificados en la línea de comando son directorios, gzip descenderá al directorio y comprimirá todos los archivos que encuentre allí (o los descomprimirá en el caso de gunzip).

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

+2

Habla específicamente de archivos zip, no archivos gzip. – dvorak

4

Usted podría utilizar encontrar junto con la bandera -exec en una sola línea de comandos para hacer el trabajo

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

Esto descomprime todo en el directorio actual, en lugar de hacerlo en relación con cada subdirectorio. Tampoco se descomprime en un directorio con el mismo nombre que cada archivo. – chuckrector

+0

Supongo que obtener el derecho -d se deja como un ejercicio para el lector. Ese lector debe tener en cuenta que -exec solo permite el uso de {} en el comando - soluciona esto llamando a sh y asignando {} a una variable. –

+0

También tenga en cuenta que -execdir a veces es preferible a -exec. En este caso, no creo que importe. –

0

Si está utilizando cygwin, la sintaxis es ligeramente diferente para el nombre base mando.

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

Me doy cuenta de que esto es muy antiguo, pero fue uno de los primeros éxitos en Google cuando estaba buscando una solución para algo similar, así que publicaré lo que hice aquí. Mi situación es un poco diferente, ya que básicamente sólo quería explotar plenamente un frasco, junto con todos los frascos contenidos en ella, así que escribió las siguientes funciones bash:

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" 
} 

Nota del <file-where-this-function-is-stored> que se necesita si usted está almacenando esto en un archivo que no se lee para un shell no interactivo como sucedía. Si está almacenando las funciones en un archivo cargado en shells no interactivos (por ejemplo, .bashrc, creo), puede soltar toda la declaración source. Espero que esto ayude a alguien.

Una pequeña advertencia - explodeFile también borra el archivo ziped; por supuesto, puede cambiar eso comentando la última línea.

10

Una solución que maneja correctamente todos los nombres de archivo (incluyendo saltos de línea) y extrae en un directorio que está en la misma ubicación que el archivo, sólo con la extensión eliminado:

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

Tenga en cuenta que usted puede hacer fácilmente que manejar más tipos de archivos (tales como .jar) mediante la adición de ellos utilizando -o, por ejemplo:

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

Otra solución interesante sería:

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; 
Cuestiones relacionadas