У меня есть множество zip-архивов, каждый из которых содержит несколько zip-архивов. Каков наилучший способ рекурсивного извлечения всех файлов, содержащихся в этом zip-архиве и его дочерних zip-архивах, которые не являются самими zip-архивами?
У меня есть множество zip-архивов, каждый из которых содержит несколько zip-архивов. Каков наилучший способ рекурсивного извлечения всех файлов, содержащихся в этом zip-архиве и его дочерних zip-архивах, которые не являются самими zip-архивами?
Ответы:
Это позволит извлечь все 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 [ "
находить . -тип f -name '*.? ar' | wc -l" -gt 0 ]; do find -type f -name "*.?ar" -exec mkdir -p '{}.dir' \; -exec unzip -d '{}.dir' -- '../{}' \; -exec rm -- '{}' \;; done
Насколько я понимаю, у вас есть 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
unzip
не делает этого, потому что способ UNIX состоит в том, чтобы делать одну вещь и делать это хорошо, а не обрабатывать все безумные особые случаи в каждом инструменте. Таким образом, вам нужно использовать оболочку (которая хорошо выполняет работу по «связыванию вещей»). Это делает это вопросом программирования, и поскольку на ВСЕ StackOverflow были даны ответы на ВСЕ возможные вопросы программирования, здесь: Как вы рекурсивно разархивируете архивы в каталоге и его подкаталогах из командной строки Unix?
Этот сценарий 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($_);
}
Самый простой способ - использовать 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.
Вы должны быть осторожны, автоматически распаковывая zip-файлы внутри zip-файлов:
http://research.swtch.com/2010/03/zip-files-all-way-down.html
Можно создать zip-файл, который создает zip-файл в качестве вывода, который создает zip-файл в качестве вывода и т. Д. И т. Д. И т. Д. То есть вы можете создать zip-файл, который является фиксированной точкой для «распаковки» программы.
Кроме того, я, кажется, вспоминаю людей, делающих zip-файлы, которые «взрываются», то есть очень маленький zip-файл распаковывается в несколько гигабайт выходных данных. Это аспект метода сжатия.
Может быть, это поможет (работал для меня):
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
}
Мне нужно было решение, подобное 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
Оформить заказ этой 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. Я автор и буду рад быстро исправить любые ошибки.