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?
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?
Respostas:
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
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
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 rm
movendo 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 shopt
linha por setopt nullglob
.
Aqui está um equivalente portátil. A condição de finalização é um pouco complicada porque find
nã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
unzip
nã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?
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($_);
}
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.zip
para descompactar todos eles ou, se você quiser usá-lo no diretório com muitos arquivos zip, use o for
loop simples :
for f in *; do atool -x $f; fi
(você precisará cd
entrar no diretório desejado com arquivos zip antes de usá-lo).
atool
O comportamento aqui não difere significativamente de descompactar, eu diria, também não extrai recursivamente arquivos ZIP.
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.
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
}
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
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.