Crear directorio si el archivo zip contiene varios archivos

8

Si un archivo contiene varios archivos en el directorio raíz, me gustaría crear un directorio con el nombre del archivo (sin extensión). Si un archivo contiene solo un directorio, me gustaría simplemente extraerlo. Supongamos que tengo el siguiente archivo:

# file: withdir.zip
somedir/alpha
somedir/beta
somedir/gamma

Si lo extraigo en el directorio actual, me gustaría tenerlo simplemente extraído ( unzip withdir.zip):

somedir/alpha
somedir/beta
somedir/gamma

Ahora asuma el siguiente archivo:

# file: nodir.zip
alpha
beta
gamma

Cuando ejecuto unzip nodir.ziptermino abarrotando el directorio actual con los tres archivos:

alpha
beta
gamma

Prefiero correr unzip -d nodir nodir.zip:

nodir/alpha
nodir/beta
nodir/gamma

Si uso nautilus y hago clic derecho en "Extraer aquí". Se comporta exactamente como debería. Pero desafortunadamente no he encontrado un interruptor de línea de comando para unzipo 7zque produzca el mismo comportamiento. ¿Cómo lograr eso? ¿Hay otras herramientas que pueda usar en su lugar (sin GUI)?

Marco
fuente

Respuestas:

7

Haría algo como esto (sintaxis zsh):

unz() (
  tmp=$(TMPDIR=. mktemp -d -- ${${argv[-1]:t:r}%.tar}.XXXXXX) || exit
  print -r >&2 "Extracting in $tmp"
  cd -- $tmp || exit
  [[ $argv[-1] = /* ]] || argv[-1]=../$argv[-1]
  (set -x; "$@"); ret=$?
  files=(*(ND[1,2]))
  case $#files in
    (0) print -r >&2 "No file created"
        rmdir -v "../$tmp";;
    (1) mv -v -- $files .. && rmdir -v ../$tmp;;
    (*) mv -vT ../$tmp ../$tmp:r;;
  esac && exit $ret
)

Es decir:

  1. crear un directorio en cualquier caso
  2. ejecuta el comando
  3. dependiendo de cuántos archivos generó el comando:
    • eliminar ese directorio (si no creó ningún archivo)
    • si creó solo un archivo / directorio, muévalo un nivel hacia arriba y descarte nuestro directorio
    • de lo contrario, intente quitar la cadena aleatoria del final de nuestro directorio temporal.

De esta manera, puedes hacer:

unz unzip foo.zip
unz tar xf foo.tar.gz

Se supone que el último argumento para el comando de extracción es el archivo a extraer. También asume herramientas GNU para las -vopciones. En los sistemas que no son GNU, puede eliminarlos y posiblemente hacer el registro a mano. mv -Ttambién es específico de GNU, y es forzar mva intentar hacer solo un cambio de nombre.

Stéphane Chazelas
fuente
3

Como unzipy 7zambos tienen un interruptor de salida a un directorio dado, puede crear un script sencillo, que los controles, cuántos archivos están en la raíz del archivo y luego agrega el interruptor si es necesario.

Con 7z esto es más fácil, ya que tiene el -sltinterruptor, lo que hace que la salida sea más legible para la máquina. Para cada archivo en el zip, la salida contendrá una Path = ...línea. Los archivos en la raíz no deben contener ninguno /en el valor.

Un script simple que escribí para descomprimir archivos de esa manera:

#!/bin/sh
for archive in "$@"; do
    # count files in root dir
    rootfiles=$(7z l -slt "${archive}" | grep -c 'Path = [^/]*$')

    # add -o switch, if more than one file in root
    # checks for >2, because path of the zip file itself is listed too
    if [ $rootfiles -gt 2 ]; then
        filename=${archive##*/}
        rootname=${filename%.*}
        opt="-o${rootname}"
    fi

    #unpack
    7z x "${opt}" "${archive}"
done

Editar: el script ahora también funciona con zip

crater2150
fuente
Este script no funciona como se esperaba. Crea un directorio withdirpara el archivo, withdir.zipaunque contiene solo un directorio en la raíz porque grep -c "Folder = -"regresa 3.
Marco
Ah, la carpeta parece ser diferente para los archivos zip.
Buscaré
@Marco: cambié el script y lo probé con archivos zip, ahora solo crea la carpeta cuando es necesario
crater2150
3

patool maneja diferentes tipos de archivos y crea un subdirectorio en caso de que el archivo contenga múltiples archivos para evitar el desorden en el directorio de trabajo con los archivos extraídos.

Crear archivo

patool create archive.zip somedirectory

Extraer archivo

patool extract archive.zip

Para obtener una lista de los formatos compatibles, use patool formats.

Marco
fuente
1

También puede usar unar , que crea un directorio contenedor de forma predeterminada cuando hay dos o más archivos de nivel superior:

$ touch 1 2
$ zip a.zip 1 2
  adding: 1 (stored 0%)
  adding: 2 (stored 0%)
$ unzip -l a.zip
Archive:  a.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  04-29-14 10:56   1
        0  04-29-14 10:56   2
 --------                   -------
        0                   2 files
$ unar a.zip
a.zip: Zip
  1  (0 B)... OK.
  2  (0 B)... OK.
Successfully extracted to "a".
$ ls a
1 2

Agregar -dpara crear siempre un directorio contenedor.

Lri
fuente