Извлечение вложенных zip-файлов

15

У меня есть множество zip-архивов, каждый из которых содержит несколько zip-архивов. Каков наилучший способ рекурсивного извлечения всех файлов, содержащихся в этом zip-архиве и его дочерних zip-архивах, которые не являются самими zip-архивами?

oadams
источник
что вы имеете в виду, извлекая вещи, которые не являются файлами zip? Вы хотите скопировать их в другое место?
phunehehe
Я не нахожу ваши требования ясными. Я считаю , Шон Дж Гофф и мою интерпретацию о равновероятно. Не могли бы вы уточнить?
Жиль "ТАК - перестать быть злым"
@ Жиль: Извините, да, это было немного неясно. Я немного изменил его, надеюсь, теперь это стало понятнее.
oadams
Я собирался опубликовать ответ, но я считаю, что он должен идти в качестве комментария: вложенные архивы увеличивают необходимое пространство! Вы, вероятно, имеете в виду формат файла Zip, а не просто gzip. каждый zip-файл уже сжат, снова сжимая его, просто создает дополнительные накладные расходы, эффективно увеличивая необходимое пространство.
Полемон
Да, я этого не делал: P. К сожалению, я подвержен этому странному способу распространения файлов.
oadams

Ответы:

13

Это позволит извлечь все zip-файлы в текущий каталог, за исключением любых zip-файлов, содержащихся в них.

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

Хотя это извлекает содержимое в текущий каталог, не все файлы будут строго находиться в этом каталоге, так как содержимое может включать в себя подкаталоги.

Если вы действительно хотите, чтобы все файлы были строго в текущем каталоге, вы можете запустить

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

Примечание: это приведет к тому, что файлы будут иметь два одинаковых имени в разных каталогах.

Если вы хотите рекурсивно извлечь все zip-файлы и zip-файлы, содержащиеся в них, следующее извлекает все zip-файлы из текущего каталога и все zip-файлы, содержащиеся в них, в текущий каталог.

while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]
do
    find . -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;
done
Шон Дж. Гофф
источник
этот цикл while мне очень помог в соревновании по этическому хакерству, где они подготовили вложенный zip-файл глубиной 31337, спасибо!
peedee
2
Вам может понравиться этот вариант, который я использую для рекурсивного извлечения содержимого из вложенных файлов ear, war, jar: gist.github.com/tyrcho/479c18795d997c201e53 Основным отличием является то, что он создает вложенную папку для каждого архива. while [ "находить . -тип f -name '*.? ar' | wc -l" -gt 0 ]; do find -type f -name "*.?ar" -exec mkdir -p '{}.dir' \; -exec unzip -d '{}.dir' -- '../{}' \; -exec rm -- '{}' \;; done
Мишель Давиот
4

Насколько я понимаю, у вас есть zip-архивы, которые сами содержат zip-архивы, и вы хотели бы разархивировать вложенные zip-архивы при извлечении одного из них.

Вот скрипт bash 4, который рекурсивно разархивирует все zip-файлы в текущем каталоге и его подкаталогах, удаляет каждый zip-файл после его распаковки и продолжает работать, пока существуют zip-файлы. Zip-файл в подкаталоге извлекается относительно этого подкаталога. Предупреждение: не проверено, сделайте резервную копию исходных файлов перед тем, как их попробовать, или замените rm, переместив zip-файл за пределы дерева каталогов .

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

Сценарий также будет работать в zsh, если вы замените shoptстроку на setopt nullglob.

Вот портативный эквивалент. Условие завершения немного сложнее, потому findчто не возвращает самопроизвольно состояние, указывающее, нашел ли он какие-либо файлы. Предупреждение: как указано выше.

while [ -n "$(find . -type f -name '*.zip' -exec sh -c '
    cd "${z%/*}" &&
    z=${z##*/} &&
    unzip -- "$z" 1>&2 &&
    rm -- "$z" &&
    echo 1
')" ]; do :; done
Жиль "ТАК - прекрати быть злым"
источник
1

unzipне делает этого, потому что способ UNIX состоит в том, чтобы делать одну вещь и делать это хорошо, а не обрабатывать все безумные особые случаи в каждом инструменте. Таким образом, вам нужно использовать оболочку (которая хорошо выполняет работу по «связыванию вещей»). Это делает это вопросом программирования, и поскольку на ВСЕ StackOverflow были даны ответы на ВСЕ возможные вопросы программирования, здесь: Как вы рекурсивно разархивируете архивы в каталоге и его подкаталогах из командной строки Unix?

Томас Фемель
источник
1
Я бы определенно не назвал «использование оболочки» вопросом программирования, а «сценарии оболочки» перечислены в FAQ как тематические
Майкл Мрозек
Я не имел в виду, что это вообще было не по теме, я просто хотел объяснить, почему это по теме в StackOverflow.
Томас Фемел
1

Этот сценарий perl извлечет каждый файл .zip в свой собственный подкаталог. Запустите скрипт несколько раз, чтобы обработать вложенные zip-файлы. Он не удаляет ZIP-файлы после извлечения, но вы можете внести это изменение, добавив вызов 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

Самый простой способ - использовать atool: http://www.nongnu.org/atool/ Это очень хороший скрипт, который использует программы zip, unzip, tar, rar и т. Д. Для извлечения любого архива.

использование atool -x package_name.zip чтобы разархивировать их все, или если вы хотите использовать его в каталоге со многими файлами zip, используйте простой forцикл:

for f in *; do atool -x $f; fi(Вы должны будете зайти cdв нужный каталог с zip-файлами, прежде чем использовать это).

Джефф Шаллер
источник
atoolПоведение здесь не отличается значительно от распаковки, я бы сказал, это также не рекурсивно извлекает файлы ZIP.
Томас Фемел
@Thomas Themel: Вы уверены, что он не рекурсивно извлекает ZIP-файлы? Он может извлекать из файлов deb tar.gz рекурсивно, но у меня нет времени проверить его с помощью вложенных zip-архивов: \
0

Вы должны быть осторожны, автоматически распаковывая zip-файлы внутри zip-файлов:

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

Можно создать zip-файл, который создает zip-файл в качестве вывода, который создает zip-файл в качестве вывода и т. Д. И т. Д. И т. Д. То есть вы можете создать zip-файл, который является фиксированной точкой для «распаковки» программы.

Кроме того, я, кажется, вспоминаю людей, делающих zip-файлы, которые «взрываются», то есть очень маленький zip-файл распаковывается в несколько гигабайт выходных данных. Это аспект метода сжатия.

Брюс Эдигер
источник
0

Может быть, это поможет (работал для меня):

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
источник
0

Мне нужно было решение, подобное Giles '2010 года, за исключением того, что мне нужно было сохранить структуру папок, а не разархивировать все в каталог верхнего уровня. Вот мой взгляд на него с тремя добавленными / измененными строками:

#!/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
источник
0

Оформить заказ этой Java-утилиты nzip для вложенных zip-файлов. Извлечение и сжатие вложенных почтовых индексов может быть легко сделано с помощью следующих команд

java -jar nzip.jar -c список -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. Я автор и буду рад быстро исправить любые ошибки.

user930412
источник