不解压缩zip文件就能够比较其中的文件差异

23

有没有办法在不解压缩的情况下,在两个 zip 文件中对两个文件执行 diff 操作?如果不行 - 是否有其他方法可以在不解压缩的情况下比较它们?

谢谢。


你只想知道这两个文件是否不同,还是想要获得可视化的差异? - gollum
如果你想知道它们是否不同,请使用 sha512 文件名1sha512 文件名2 并查看输出是否相同。 - vishal
相关链接:https://stackoverflow.com/q/8001663 - undefined
10个回答

13

综合目前的回应,以下bash函数将比较zip文件中的文件列表。列表包括详细输出(unzip -v),因此可以比较校验和。输出按文件名排序(sort -k8),以允许并排比较,并展开差异输出(W200),以便在并排视图中看到文件名。

function zipdiff() { diff -W200 -y <(unzip -vql "$1" | sort -k8) <(unzip -vql "$2" | sort -k8); }

您可以将此内容添加到~/.bashrc文件中,以便在任何控制台中使用。它可与zipdiff a.zip b.zip一起使用。将输出导入less或重定向到文件对于大型zip文件很有帮助。


1
非常有帮助,谢谢。我发现根据下面另一条评论的建议,添加--suppress-common-lines可以使它变得更好。 - Steve Kehlet
如果您想忽略日期差异,只比较 (哈希值,大小,路径): function zipcdiff() { A='{printf("%8sB %s %s\n",$1,$7,$8)}'; diff <(unzip -vqql "$1" | awk "$A" | sort -k3) <(unzip -vqql "$2" | awk "$A" | sort -k3); }。当内容相等时, 输出为空。用于检查确定性构建的有用工具。 - geekley

8

7
在我的使用中,将 --suppress-common-lines 标志添加到命令中可以只显示不同的行,效果非常好:diff -y <(unzip -l foo.zip) <(unzip -l bar.zip) --suppress-common-lines - Kostas Minaidis
3
我用了function zipdiff() { diff -y <(unzip -l $1) <(unzip -l $2) --suppress-common-lines; }这个函数,它完美地完成了我想做的事情。 - Velizar Hristov
1
这不会检测到对现有文件的更改,即使它恰好保持相同的大小。使用-vql而不是-l可以打印校验和,但这些校验和是CRC32(这意味着它们不能可靠地检测到故意篡改,就像加密哈希函数一样)。 - Pr0methean

6

我想以易读的格式获取压缩文件中文件间的实际差异。以下是我为此目的编写的一个Bash函数,它利用了git。如果您已经将git作为正常工作流程的一部分使用并可以读取git diffs,则具有良好的用户体验。

# usage: zipdiff before.zip after.zip
function zipdiff {
  current=$(pwd)
  before="$current/$1"
  after="$current/$2"
  tempdir=$(mktemp -d)
  cd "$tempdir"
  git init &> /dev/null
  unzip -qq "$before" *
  git add . &> /dev/null
  git commit -m "before" &> /dev/null
  rm -rf "$tempdir/*"  
  yes | unzip -qq "$after" * &> /dev/null
  git add .
  git diff --cached
  cd "$current"
  rm -rf "$tempdir"
}


6

仅压缩文件内容

简述

对比两个zip文件(a.zipb.zip)的命令为:

diff \
  <(unzip -vqq a.zip  | awk '{$2=""; $3=""; $4=""; $5=""; $6=""; print}' | sort -k3 -f) \
  <(unzip -vqq b.zip  | awk '{$2=""; $3=""; $4=""; $5=""; $6=""; print}' | sort -k3 -f)

解释

我正在寻找一种比较zip文件中存储的文件内容而非其他元数据的方法。请考虑以下情况:

$ echo foo > foo.txt
$ zip now.zip foo.txt
  adding: foo.txt (stored 0%)
$ zip later.zip foo.txt
  adding: foo.txt (stored 0%)
$ diff now.zip later.zip 
Binary files now.zip and later.zip differ

从概念上讲,这是没有意义的;我在相同的输入上运行了相同的命令,却得到了2个不同的输出!这种差异是由元数据引起的,元数据存储了文件添加日期!

$ unzip -v now.zip 
Archive:  now.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       4  Stored        4   0% 04-08-2020 23:27 7e3265a8  foo.txt
--------          -------  ---                            -------
       4                4   0%                            1 file
$ unzip -v later.zip
Archive:  later.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       4  Stored        4   0% 04-08-2020 23:28 7e3265a8  foo.txt
--------          -------  ---                            -------
       4                4   0%                            1 file

注:为了更清晰,我手动编辑了第二个文件的时间,将其从23:27更改为23:28。尽管这些秒数未在命令输出中表示,并且它们存储在文件本身的字段中(在我的情况下有所不同,二进制差异仍将失败),但我们必须忽略日期字段才能仅对文件进行比较。使用unzip -vqq可以获得更好的摘要:
$ unzip -vqq now.zip
       4  Stored        4   0% 04-08-2020 23:27 7e3265a8  foo.txt

因此,让我们屏蔽字段(我们不关心日期或压缩指标),并对文件进行排序:

$ unzip -vqq now.zip  | awk '{$2=""; $3=""; $4=""; $5=""; $6=""; print}' | sort -k3 -f
4      7e3265a8 foo.txt

太棒了,正是我所寻找的! - Patrik Iselind

5

如果你想比较两个文件(即查看它们的不同之处),你必须将它们提取出来——即使只是到内存中!

为了查看两个zip文件中的两个文件的差异,你可以像这样操作(没有错误检查或任何其他操作):

# define a little bash function
function zipdiff () { diff -u <(unzip -p $1 $2) <(unzip -p $3 $4); }

# test it: create a.zip and b.zip, each with a different file.txt
echo hello >file.txt; zip a.zip file.txt
echo world >file.txt; zip b.zip file.txt

zipdiff a.zip file.txt b.zip file.txt
--- /dev/fd/63  2016-02-23 18:18:09.000000000 +0100
+++ /dev/fd/62  2016-02-23 18:18:09.000000000 +0100
@@ -1 +1 @@
-hello
+world

注意:unzip -p命令会将文件提取到管道(stdout)中。
如果你只是想知道这些文件是否不同,你可以使用检验和来检查它们。
unzip -v -l zipfile [file_to_inspect]

注意: -v 表示详细模式,-l 表示列出内容。
unzip -v -l a.zip 
Archive:  a.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       6  Stored        6   0% 2016-02-23 18:23 363a3020  file.txt
--------          -------  ---                            -------
       6                6   0%                            1 file

unzip -v -l b.zip 
Archive:  b.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       6  Stored        6   0% 2016-02-23 18:23 dd3861a8  file.txt
--------          -------  ---                            -------
       6                6   0%                            1 file 

在上面的示例中,您可以看到校验和(CRC-32)是不同的。
您可能还对此项目感兴趣: https://github.com/nhnb/zipdiff

1
通过后处理zipcmp的输出,您可以递归地遍历存档文件,以获取它们之间差异的更详细摘要。
#!/bin/bash

# process zipcmp's output to do true diffs of archive contents
# 1. grep removes the '+++' and '---' from zipcmp's output
# 2. awk prints the final column of output
# 3. sort | uniq to dedupe
for badfile in $(zipcmp ${1?No first zip} ${2?No second zip} \
    | grep -Ev '^[+-]{3}' \
    | awk '{print $NF}' \
    | sort | uniq);
do
    echo "diffing $badfile"
    diff <(unzip -p $1 $badfile) <(unzip -p $2 $badfile) ;
done;


0

如果您只需要检查文件是否相等,则可以比较存储在存档本地头字段/中央目录中的CRC32校验和。


0

存在一些命令行工具:

  1. diffzips.pl,使用Perl编写。
  2. zipdiff,使用Java编写。
  3. zipdiff,前一个的.NET端口。
  4. zipcmp,使用C编写,来自libzip库。
  5. zcmpzdiff,来自gzip,可用于zip文件。

我是diffzips.pl的快乐用户,用它来比较epub文件的内容。diffzips.pl还有一个优点,就是递归比较父zip中的zip文件。


0

https://www.diffnow.com/compare-files这样的网络工具提供了非常好的视觉信息,可以显示压缩文件中哪些文件已更改:

enter image description here

这对于不太大的zip文件非常方便,而且无需安装任何东西。这不仅适用于Linux,还适用于其他操作系统,包括Windows和Mac。

其他答案中讨论的工具显然提供了更高级的选项,并且对于较大的zip文件可能更快。


0
在开源库Zip-Ada中,comp_zip工具(可在此处此处获取)执行无需提取的比较:对a.zip文件的内容、缺失于b.zip文件中的文件以及两者的完整性进行检查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接