重新压缩文件而不创建临时文件

重新压缩文件而不创建临时文件

也许我最好先从用例开始。
我有一个包含许多文件的大型 zip 文件,我怀疑它最初是在低压缩级别下压缩的。

我想从该文件创建一个新的 zip 文件(或者不是新的,希望是就地的),以确保它被很好地压缩(-9),而无需先将其解压缩到磁盘(出于各种原因,例如大小和挂载的 NFS)。因此,虽然我可以这样做

mkdir tmp/ && unzip -d tmp/ A.zip && cd tmp/ && zip -r -9 ../B.zip *; rm -rf tmp/ A.zip

这将[暂时]产生大量数据(解压文件并在被删除B.zip之前存在A.zip)。
我真正想要的是类似这样的东西:

rezip -9 A.zip

或者,选择一个B.zip

unzip -<output to stdout> A.zip | zip -9 B.zip && rm -f A.zip

但我意识到这可能实际上是不可能的,因为管道将用于多个文件,而文件名等内容将会丢失。

因此,我想知道是否有办法在每个文件上执行一些代码,例如find -exec <command>

unzip A.zip -exec zip -r B.zip && rm -f A.zip

但同样,不确定这将如何工作,或者,如果这不是由unzip/实现的zip,是否存在可以执行的命令。

我已经将我目前仍在使用临时的单个文件解决方法作为答案,因为它可能会对某些人有所帮助,尽管它不被接受,因为它没有回答问题不允许临时工

答案1

已经有一段时间了,但下面是具体操作方法。
适用于名称中带有空格的文件和子目录。

zipinfo -1 A.zip | while read filename
do
    unzip -p A.zip "$filename" | zip -9 A.zip -
    zip --delete A.zip "$filename"
    printf "@ -\n@=$filename\n" | zipnote -w A.zip
done

答案2

我找到了一个更好的解决方案:

unzip -p original.zip | zip -9 new.zip -

unzip -p 告诉 unzip 将输出发送到 stdout。zip 命令的最后一个破折号告诉它从 stdin 读取。

如果确实需要,您仍然需要将 new.zip 重命名为 original.zip。

答案3

开源Zip-Ada项目正好有这样一个 rezip 工具。

  1. 获取/下载源代码
  2. 使用命令构建gnatmake -P zipada(您可以通过 apt 或 yum 获取 GNAT)
  3. 您现在有一个具有以下选项的二进制 rezip:

Usage: rezip [options] archive(s)[.zip]

Options:  -defl     : repack archive only with the Deflate
                    subformat (most compatible)
          -fast_dec : repack archive only with fast decompressing subformats
          -int      : use internal Zip-Ada algorithms only, no external call
          -touch    : set time stamps to now
          -lower    : set full file names to lower case
          -del_comm : delete comment
          -comp     : compare original and repacked archives (paranoid mode)
          -rs=n     : loop many times over a single compression approach
                        having randomization, and keep optimum when size is
                        stable after n attempts in a row

首先,我建议使用-defl-int选项(值得注意的是,-defl将使生成的 Zip 文件与旧工具保持兼容unzip)。

例如,命令如下./rezip -int -defl -comp A.zip

相关内容