ti-enxame.com

Extração de arquivos Zip aninhados

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 neste arquivo Zip e seus arquivos Zip filho, que não são os próprios arquivos Zip?

15
oadams

Isso irá 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 terminarão estritamente neste diretório, pois o conteúdo pode incluir subdiretórios.

Se você realmente deseja todos os arquivos estritamente no diretório atual, você pode executar

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

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

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

while [ "`find . -type f -name '*.Zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.Zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
13
Shawn J. Goff

Pelo que entendi, você tem arquivos Zip que contêm arquivos Zip e gostaria de descompactar os zips aninhados sempre que algum fosse extraído.

Aqui está um script bash 4 que descompacta todos os zips do diretório atual e seus subdiretórios recursivamente, remove cada arquivo Zip depois de 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 tentar ou substitua rm movendo o arquivo Zip 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á em zsh se você substituir a linha shopt por setopt nullglob.

Aqui está um equivalente portátil. A condição de encerramento é um pouco complicada porque find não retorna espontaneamente um status para indicar se encontrou algum arquivo. Aviso: 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
4

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

Usar atool -x package_name.Zip para descompactá-los todos ou se quiser usá-lo em um diretório com muitos arquivos Zip, use o loop for simples:

for f in *; do atool -x $f; fi (você terá que cd no diretório desejado com os arquivos Zip antes de usá-lo).

1
user2648

Este script Perl extrairá cada arquivo .Zip em seu próprio subdiretório. Execute o script mais de uma vez para lidar com arquivos Zip aninhados. Ele não exclui os 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($_);
}
1
John

Verifique este Java nzip para arquivos Zip aninhados. Extrair e compactar zips aninhados pode ser feito facilmente usando os seguintes 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"

PS. Eu sou o autor e terei todo o gosto em corrigir quaisquer erros rapidamente.

0
user930412

Eu precisava de uma solução como a de Giles de 2010, exceto que precisava preservar a estrutura de pastas, não descompactar tudo no diretório de nível superior. Aqui está minha opinião sobre ele 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
0
steaknchips

Você deve ter cuidado ao descompactar automaticamente os arquivos Zip dentro dos arquivos Zip:

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

É possível inventar um arquivo Zip que produz um arquivo Zip como saída, que produz um arquivo Zip como saída, etc etc etc. Ou seja, você pode fazer um arquivo Zip que é um unzip fixo de "descompactar" o programa.

Além disso, acho que me lembro de pessoas fazendo arquivos Zip que "explodiam", ou seja, um arquivo Zip muito pequeno descompactava para vários gigabytes de saída. Esta é uma faceta do método de compressão.

0
Bruce Ediger

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

}
0
user151061