提取嵌套的zip文件


15

我有许多zip档案,每个档案都包含许多zip档案。递归提取此zip存档及其子zip存档中包含的所有文件的最佳方法是什么,而不是zip存档本身?


提取不是zip文件的内容是什么意思?您想将它们复制到另一个地方吗?
phunehehe

我认为您的要求不明确。我发现Shawn J. Goff我的解释也差不多。你能澄清一下吗?
吉尔斯(Gilles)“所以,别再邪恶了”,2010年

@吉尔斯:对不起,是的,还不清楚。我对其进行了一些更改,希望现在可以更加清楚了。
oadams 2010年

我本来打算发布一个答案,但我认为它应该作为注释:Nested Archives 增加了您所需的空间!您可能是指Zip文件格式,而不仅仅是gzip。每个zip文件已经被压缩,再次对其进行压缩,只会产生更多开销,从而有效地增加了所需的空间。
polemon

是的,我没有这么做:P。不幸的是,我受到这种奇怪的文件分发方式的困扰。
oadams's

Answers:


13

这会将所有压缩文件解压缩到当前目录中,其中不包含其中的任何压缩文件。

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级,谢谢!
撒尿2015年

2
您可能会喜欢这种变体,我用它从嵌套的耳朵,战争,罐子文件中递归地提取内容: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
Michel Daviot,2016年

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

如果将shopt行替换为,脚本也将在zsh中工作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中列为主题
Michael Mrozek

我并不是要暗示它根本不在这里,我只是想证明为什么它在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; ficd使用此文件之前,您必须将其包含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文件,可以解压缩到数GB的输出。这是压缩方法的一个方面。


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

}

0

我需要一个像2010年的Giles一样的解决方案,除了我需要保留文件夹结构,而不是将所有内容都解压缩到顶层目录中。这是我对他的看法,添加/更改了三行:

#!/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

检出此基于Java的实用程序nzip中的嵌套zip文件。使用以下命令可以轻松地提取和压缩嵌套的zip。

java -jar nzip.jar -c list -s readme.zip

java -jar nzip.jar -c提取-s“ C:\ project \ readme.zip” -t自述文件

java -jar nzip.jar -c compress -s自述文件-t“ C:\ project \ readme.zip”

PS。我是作者,很乐意迅速修复所有错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.