¿Equivalente a "--strip-components = 1" de tar en descomprimir?

49

Tengo una secuencia de comandos que extrae un archivo tar.gz a un subdirectorio especificado mysubfolder :

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;

¿Hay alguna forma equivalente de hacer esto con un archivo zip?

frigg
fuente
2
Solo usa bsdtar
drizzt el

Respuestas:

26

Como dijo Mathias, unzipno tiene esa opción, pero un script bash de una sola línea puede hacer el trabajo.

El problema es: el mejor enfoque depende de su diseño de archivo. Una solución que asume que un único directorio de nivel superior fallará miserablemente si el contenido está directamente en la raíz del archivo (piense /a/foo /b/foo /fooy el caos de la eliminación /ay /b).

Y ocurre el mismo error con tar --strip-component. No existe una solución única para todos.

Por lo tanto, para quitar el directorio raíz, suponiendo que no es uno (y solamente uno):

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"

Solo asegúrese de que los archivos / directorios de segundo nivel no tengan el mismo nombre del padre de nivel superior (por ejemplo /foo/foo). Pero /foo/bar/fooya /foo/bar/barestán bien. Si lo hacen, o si solo quieres estar seguro, puedes usar un directorio temporal para la extracción:

temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"

Si está utilizando Bash, puede probar si el nivel superior es un directorio único o no:

f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"

Hablando de Bash, debe activar dotglobpara incluir archivos ocultos, y puede envolver todo en una sola función práctica:

unzip-strip() (
    local zip=$1
    local dest=${2:-.}
    local temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
    shopt -s dotglob && local f=("$temp"/*) &&
    if (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] ; then
        mv "$temp"/*/* "$dest"
    else
        mv "$temp"/* "$dest"
    fi && rmdir "$temp"/* "$temp"
)

Ahora pon eso en tu ~/.bashrco ~/.profiley nunca más tendrás que preocuparte por eso. Simplemente use como:

unzip-strip sourcefile.zip mysubfolder

(observe que se creará automáticamente mysubfolderpara usted si no existe)

MestreLion
fuente
Esto no se descomprimirá en una estructura de directorio existente como esperaba (intenté usar. En lugar de mysubfolder). Terminé simplemente descomprimiendo (descomprimir zip-with-top-dir.zip) y luego copiando (cp -rv extraído-top-zip-dir / *.).
catgofire
4

No pude encontrar esa opción en las páginas del manualunzip , así que me temo que esto es imposible. :(

Sin embargo, (dependiendo de la situación) podría solucionarlo. Por ejemplo, si está seguro de que el único directorio de nivel superior en el archivo zip se nombra foo-seguido de un número de versión, puede hacer algo como esto:

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder
Mathias Bynens
fuente
Enfoque agradable, pero un poco incompleto: aún tendrá foo * dir con todo el contenido extraído.
MestreLion
Sí, no agregué rm -rf foo-*a propósito, ya que eso es potencialmente peligroso. ¿Qué pasa si ya había una carpeta con nombre foo-bar? Tenga en cuenta que la extracción se realiza dentro de la /tmpcarpeta, que se vacía automáticamente de vez en cuando.
Mathias Bynens
Es por eso que encadené las operaciones usando &&: un paso dado solo ocurre si el paso anterior fue exitoso, por lo que el último (el rm) solo se ejecuta si todos los pasos se completaron sin error.
MestreLion
2
Esa es también la razón por la que uno nunca debe usar /tmp/some-hardcoded-folder-namecomo carpeta temporal, sino que debe usar mktemppara eso: garantiza que no habrá tal carpeta existente. Mira mi respuesta a continuación.
MestreLion
1

Puede usar -jpara desechar rutas (no haga directorios). Esto solo se recomienda para archivos de nivel único algo comunes. Los archivos con estructuras de directorio multinivel se aplanarán, lo que incluso podría provocar conflictos de nombres para que los archivos se extraigan.

Desde la página de manual de descomprimir:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
Pedro Rodrigues
fuente