Wyodrębnianie zagnieżdżonych plików zip

15

Mam liczne archiwa zip, z których każde zawiera wiele archiwów zip. Jaki jest najlepszy sposób rekurencyjnego wyodrębnienia wszystkich plików zawartych w tym archiwum zip i jego podrzędnych archiwach zip, które same nie są archiwami zip?

oadams
źródło
co masz na myśli przez wyodrębnianie rzeczy, które nie są plikami zip? chcesz skopiować je w inne miejsce?
phunehehe
Nie uznaję twoich wymagań za jasne. Uważam Shawna J. Goffa i moją interpretację za równie prawdopodobną. Czy możesz to wyjaśnić?
Gilles „SO- przestań być zły”
@Gilles: Przepraszam, tak, to było trochę niejasne. Trochę go zmieniłem, mam nadzieję, że teraz jest bardziej przejrzysty.
oadams
Zamierzałem opublikować odpowiedź, ale uważam, że powinna ona zostać skomentowana: zagnieżdżone archiwa zwiększają potrzebną przestrzeń! Prawdopodobnie masz na myśli format pliku Zip, a nie tylko gzip. każdy plik zip jest już skompresowany, kompresując go ponownie, po prostu tworzy więcej narzutu, skutecznie zwiększając potrzebną przestrzeń.
polemon
Tak, nie zrobiłem tego: P. Niestety podlegam temu dziwnemu sposobowi dystrybucji plików.
oadams

Odpowiedzi:

13

Spowoduje to wyodrębnienie wszystkich plików zip do bieżącego katalogu, z wyjątkiem zawartych w nich plików zip.

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

Mimo że wyodrębnia to zawartość do bieżącego katalogu, nie wszystkie pliki znajdą się w tym katalogu ściśle, ponieważ zawartość może zawierać podkatalogi.

Jeśli naprawdę chcesz, aby wszystkie pliki były ściśle w bieżącym katalogu, możesz uruchomić

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

Uwaga: spowoduje to zamknięcie plików, jeśli w różnych katalogach są dwa o tej samej nazwie.

Jeśli chcesz rekurencyjnie wyodrębnić wszystkie pliki zip i zawarte w nich zamki błyskawiczne, poniższe wypakuje wszystkie pliki zip z bieżącego katalogu i wszystkie zawarte w nich zamki błyskawiczne do bieżącego katalogu.

while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
Shawn J. Goff
źródło
ta pętla while bardzo mi pomogła w konkursie etycznego hakowania, w którym przygotowali zagnieżdżony plik zip o głębokości 31337 poziomów, dzięki!
peedee
2
może ci się spodobać ten wariant, którego używam do rekurencyjnego wydobywania zawartości z zagnieżdżonych plików ucha, wojny, słoika: gist.github.com/tyrcho/479c18795d997c201e53 Główną różnicą jest to, że tworzy zagnieżdżony folder dla każdego archiwum. while [ "odnaleźć . -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

O ile rozumiem, masz archiwa zip, które same zawierają archiwa zip i chciałbyś rozpakować zagnieżdżone zamki błyskawiczne za każdym razem, gdy są one rozpakowywane.

Oto skrypt bash 4, który rozpakowuje wszystkie zamki błyskawiczne w bieżącym katalogu i jego podkatalogach rekurencyjnie, usuwa każdy plik zip po rozpakowaniu i działa tak długo, jak długo są pliki zip. Plik zip w podkatalogu jest wyodrębniany względem tego podkatalogu. Ostrzeżenie: niesprawdzone, wykonaj kopię zapasową oryginalnych plików przed wypróbowaniem lub zamień rm, przenosząc plik zip poza drzewo katalogów .

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

Skrypt będzie również działał w Zsh, jeśli zastąpisz shoptlinię setopt nullglob.

Oto przenośny odpowiednik. Warunek zakończenia jest nieco skomplikowany, ponieważ findnie spontanicznie zwraca status wskazujący, czy znalazł jakieś pliki. Ostrzeżenie: jak wyżej.

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- przestań być zły”
źródło
1

unzipnie robi tego, ponieważ UNIX to zrobić jedną rzecz i zrobić to dobrze, a nie obsługiwać wszystkich szalonych specjalnych przypadków w każdym narzędziu. Dlatego musisz użyć powłoki (która dobrze wykonuje zadanie „powiązania ze sobą”). To sprawia, że ​​jest to pytanie programistyczne, a ponieważ na StackOverflow udzielono odpowiedzi na WSZYSTKIE możliwe pytania programistyczne, tutaj: Jak rekurencyjnie rozpakowujesz archiwa w katalogu i jego podkatalogach z wiersza poleceń Uniksa?

Thomas Themel
źródło
1
Zdecydowanie nie nazwałbym „używaniem powłoki” pytaniem programistycznym, a „skryptowanie powłoki” jest wymienione w FAQ jako na temat
Michael Mrozek
Nie chciałem sugerować, że w ogóle nie jest to tematem, chciałem tylko uzasadnić, dlaczego jest on tematem na StackOverflow.
Thomas Themel
1

Ten skrypt perla wyodrębni każdy plik .zip do własnego podkatalogu. Uruchom skrypt więcej niż jeden raz, aby obsłużyć zagnieżdżone pliki zip. Nie usuwa plików .zip po rozpakowaniu, ale możesz to zmienić, dodając wywołanie 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($_);
}
Jan
źródło
1

Najprostszym sposobem jest użycie atool: http://www.nongnu.org/atool/ Jest to bardzo dobry skrypt, który używa programów zip, unzip, tar, rar itp. W celu wyodrębnienia dowolnego archiwum.

Użyj, atool -x package_name.zipaby rozpakować je wszystkie lub jeśli chcesz użyć go w katalogu z wieloma plikami zip, użyj prostej forpętli:

for f in *; do atool -x $f; fi(będziesz musiał przejść cddo pożądanego katalogu z plikami zip przed użyciem).

Jeff Schaller
źródło
atoolZachowanie tutaj nie różni się znacząco od rozpakowania powiedziałbym, że nie rekurencyjnie wyodrębnia plików ZIP.
Thomas Themel
@Thomas Themel: Czy na pewno nie rekurencyjnie wyodrębnia plików ZIP? Może wyciągać z plików deb tar.gz rekurencyjnie, ale nie mam czasu, aby przetestować go za pomocą zagnieżdżonych archiwów zip: \
0

Musisz zachować ostrożność, automatycznie rozpakowując pliki zip wewnątrz plików zip:

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

Możliwe jest wymyślenie pliku zip, który tworzy plik zip jako plik wyjściowy, który tworzy plik zip jako plik wyjściowy itp. Itd. Oznacza to, że możesz utworzyć plik zip, który jest stałą cechą „rozpakowania” programu.

Wydaje mi się też, że pamiętam ludzi tworzących pliki zip, które „eksplodowałyby”, czyli bardzo mały plik zip rozpakowałby się do wielu gigabajtów danych wyjściowych. Jest to aspekt metody kompresji.

Bruce Ediger
źródło
0

Może to pomoże (działało dla mnie):

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

}
użytkownik151061
źródło
0

Potrzebowałem rozwiązania takiego jak Giles z 2010 roku, z wyjątkiem tego, że musiałem zachować strukturę folderów, a nie rozpakowywać wszystkiego do katalogu najwyższego poziomu. Oto moje spojrzenie na jego z trzema liniami dodanymi / zmienionymi:

#!/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
źródło
0

Pobierz to nzip oparte na Javie narzędzie do zagnieżdżonych plików zip. Wyodrębnianie i kompresowanie zagnieżdżonych zamków błyskawicznych można łatwo wykonać za pomocą następujących poleceń

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 kompres -s readme -t "C: \ project \ readme.zip"

PS. Jestem autorem i chętnie naprawię wszelkie błędy.

użytkownik930412
źródło