Extraindo arquivos zip aninhados

15

Eu tenho vários arquivos zip, cada um dos quais contém vários arquivos zip. Qual é a melhor maneira de extrair recursivamente todos os arquivos contidos nesse arquivo zip e em seus arquivos zip filhos, que não são eles próprios?

oadams
fonte
o que você quer dizer com extrair coisas que não são arquivos zip? você quer copiá-los para outro lugar?
Phdhehehe
Não acho seus requisitos claros. Acho Shawn J. Goff e minha interpretação igualmente prováveis. Você poderia esclarecer?
Gilles 'SO- stop be evil'
@Gilles: Desculpe, sim, era um pouco claro. Eu mudei um pouco, espero que esteja mais claro agora.
Oadams 28/11/2010
Eu ia postar uma resposta, mas acredito que deveria ser um comentário: os arquivos aninhados aumentam o espaço que você precisa! Você provavelmente quer dizer o formato do arquivo Zip, não apenas o gzip. todo arquivo zip já está compactado, compactando-o novamente, apenas cria mais sobrecarga, aumentando efetivamente o espaço necessário.
Polemon
Sim, eu não fiz: P. Infelizmente, estou sujeito a essa maneira bizarra de distribuir arquivos.
Oadams

Respostas:

13

Isso extrairá todos os arquivos zip para o diretório atual, excluindo quaisquer arquivos zip contidos neles.

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

Embora isso extraia o conteúdo para o diretório atual, nem todos os arquivos acabam estritamente nesse diretório, pois o conteúdo pode incluir subdiretórios.

Se você realmente quisesse todos os arquivos estritamente no diretório atual, poderá executar

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

Nota: isso estraga os arquivos se houver dois com o mesmo nome em diretórios diferentes.

Se você deseja extrair recursivamente todos os arquivos zip e zips contidos, o seguinte extrai todos os arquivos zip no diretório atual e todos os zips contidos neles no diretório atual.

while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
Shawn J. Goff
fonte
esse loop while me ajudou muito em uma competição ética de hackers, onde eles haviam preparado um arquivo zip aninhado com 31337 níveis de profundidade, obrigado!
Peedee
2
você pode gostar dessa variante que eu uso para extrair recursivamente o conteúdo dos arquivos ear, war, jar aninhados : gist.github.com/tyrcho/479c18795d997c201e53 A principal diferença é que ele cria uma pasta aninhada para cada arquivo morto . 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

Até onde eu entendi, você tem arquivos zip que contêm arquivos zip e gostaria de descompactar zips aninhados sempre que um for extraído.

Aqui está um script do bash 4 que descompacta todos os zips no diretório atual e seus subdiretórios recursivamente, remove cada arquivo zip depois de ter sido descompactado e continua enquanto houver arquivos zip. Um arquivo zip em um subdiretório é extraído em relação a esse subdiretório. Aviso: não testado, faça um backup dos arquivos originais antes de testá-lo ou substitua rmmovendo o arquivo zip para fora da árvore de diretórios .

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

O script também funcionará no zsh se você substituir a shoptlinha por setopt nullglob.

Aqui está um equivalente portátil. A condição de finalização é um pouco complicada porque findnão retorna espontaneamente um status para indicar se encontrou algum arquivo. Atenção: como acima.

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- parar de ser mau'
fonte
1

unzipnão faz isso, porque a maneira UNIX é fazer uma coisa e fazer isso bem, não lidar com todos os casos especiais loucos em todas as ferramentas. Portanto, você precisa usar o shell (que faz o trabalho de "amarrar as coisas" bem). Isso o torna uma questão de programação, e como TODAS as possíveis perguntas de programação foram respondidas no StackOverflow, aqui: Como você descompacta recursivamente os arquivos em um diretório e seus subdiretórios da linha de comando do Unix?

Thomas Themel
fonte
1
Definitivamente, eu não chamaria de "usar o shell" uma questão de programação, e "script de shell" está listado no FAQ como no tópico
Michael Mrozek
Eu não pretendia sugerir que estava fora do tópico aqui, só queria justificar por que ele está no tópico no StackOverflow.
Thomas Themel
1

Esse script perl extrairá cada arquivo .zip em seu próprio subdiretório. Execute o script mais de uma vez para manipular arquivos zip aninhados. Ele não exclui arquivos .zip após a extração, mas você pode fazer essa alteração adicionando uma chamada 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
fonte
1

A maneira mais fácil é usar o atool: http://www.nongnu.org/atool/ É um script muito bom que usa programas zip, descompactar, tar, rar etc. para extrair qualquer arquivo.

Use atool -x package_name.zippara descompactar todos eles ou, se você quiser usá-lo no diretório com muitos arquivos zip, use o forloop simples :

for f in *; do atool -x $f; fi(você precisará cdentrar no diretório desejado com arquivos zip antes de usá-lo).

Jeff Schaller
fonte
atoolO comportamento aqui não difere significativamente de descompactar, eu diria, também não extrai recursivamente arquivos ZIP.
Thomas Themel
@ Thomas Themel: Você tem certeza de que não extrai recursivamente arquivos ZIP? Ele pode extrair dos arquivos deb tar.gz de forma recorrente, mas não tenho tempo atm para testá-lo com arquivos zip aninhados: \
0

Você deve tomar cuidado para descompactar automaticamente arquivos zip dentro de arquivos zip:

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

É possível inventar um arquivo zip que produza um arquivo zip como saída, que produz um arquivo zip como saída, etc etc etc. Ou seja, você pode criar um arquivo zip que seja um ponto fixo para "descompactar" o programa.

Além disso, pareço me lembrar de pessoas criando arquivos zip que "explodiriam", ou seja, um arquivo zip muito pequeno descompactaria para vários gigabytes de saída. Essa é uma faceta do método de compactação.

Bruce Ediger
fonte
0

Talvez isso ajude (funcionou para mim):

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

}
user151061
fonte
0

Eu precisava de uma solução como a de Giles em 2010, exceto que eu precisava preservar a estrutura da pasta, não descompactar tudo no diretório de nível superior. Aqui está a minha opinião sobre a dele com três linhas adicionadas / alteradas:

#!/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
steaknchips
fonte
0

Confira este utilitário nzip baseado em java para arquivos zip aninhados. A extração e compactação de zips aninhados pode ser feita facilmente usando os seguintes comandos

java -jar nzip.jar -c list -s readme.zip

java -jar nzip.jar -c extrai -s "C: \ projeto \ readme.zip" -t leia-me

java -jar nzip.jar -c comprime -s readme -t "C: \ projeto \ readme.zip"

PS. Eu sou o autor e ficarei feliz em corrigir quaisquer erros rapidamente.

user930412
fonte