40

我想知道两个 tarball 文件是否包含相同的文件,就文件名和文件内容而言,不包括日期、用户、组等元数据。

但是,有一些限制:首先,我在制作tar文件时无法控制是否包含元数据,实际上,tar文件总是包含元数据,所以直接比较两个tar文件是行不通的。其次,由于某些 tar 文件太大,我无法将它们解压到临时目录中并逐个比较包含的文件。(我知道如果我可以将 file1.tar 解压到 file1/ 中,我可以通过在 file/ 中调用 'tar -dvf file2.tar' 来比较它们。但通常我连其中一个都无法解压)

知道如何比较两个 tar 文件吗?如果可以在 SHELL 脚本中完成就更好了。或者,有什么方法可以在不实际解压缩 tarball 的情况下获取每个子文件的校验和?

谢谢,

4

12 回答 12

20

还尝试使用 pkgdiff来可视化包之间的差异(检测添加/删除/重命名的文件和更改的内容,如果未更改则以零代码存在):

pkgdiff PKG-0.tgz PKG-1.tgz

在此处输入图像描述

在此处输入图像描述

于 2016-03-01T21:58:24.530 回答
11

Are you controlling the creation of these tar files?
If so, the best trick would be to create a MD5 checksum and store it in a file within the archive itself. Then, when you want to compare two files, you just extract this checksum files and compare them.


If you can afford to extract just one tar file, you can use the --diff option of tar to look for differences with the contents of other tar file.


One more crude trick if you are fine with just a comparison of the filenames and their sizes.
Remember, this does not guarantee that the other files are same!

execute a tar tvf to list the contents of each file and store the outputs in two different files. then, slice out everything besides the filename and size columns. Preferably sort the two files too. Then, just do a file diff between the two lists.

Just remember that this last scheme does not really do checksum.

Sample tar and output (all files are zero size in this example).

$ tar tvfj pack1.tar.bz2
drwxr-xr-x user/group 0 2009-06-23 10:29:51 dir1/
-rw-r--r-- user/group 0 2009-06-23 10:29:50 dir1/file1
-rw-r--r-- user/group 0 2009-06-23 10:29:51 dir1/file2
drwxr-xr-x user/group 0 2009-06-23 10:29:59 dir2/
-rw-r--r-- user/group 0 2009-06-23 10:29:57 dir2/file1
-rw-r--r-- user/group 0 2009-06-23 10:29:59 dir2/file3
drwxr-xr-x user/group 0 2009-06-23 10:29:45 dir3/

Command to generate sorted name/size list

$ tar tvfj pack1.tar.bz2 | awk '{printf "%10s %s\n",$3,$6}' | sort -k 2
0 dir1/
0 dir1/file1
0 dir1/file2
0 dir2/
0 dir2/file1
0 dir2/file3
0 dir3/

You can take two such sorted lists and diff them.
You can also use the date and time columns if that works for you.

于 2009-06-23T04:50:31.277 回答
7

编辑:查看@StéphaneGourichon 的评论

我意识到这是一个迟到的回复,但我在尝试实现同样的事情时遇到了这个问题。我实现的解决方案将 tar 输出到标准输出,并将其通过管道传输到您选择的任何哈希:

tar -xOzf archive.tar.gz | sort | sha1sum

请注意,参数的顺序很重要;特别是O使用标准输出的信号。

于 2015-03-30T22:45:28.463 回答
7

tarsum几乎是你所需要的。获取它的输出,通过 sort 运行它以获得相同的顺序,然后将两者与 diff 进行比较。这应该让你有一个基本的实现,并且通过修改 Python 代码来完成整个工作,将这些步骤拉入主程序就足够容易了。

于 2009-06-23T05:18:22.130 回答
6

这是我的变体,它也在检查 unix 权限:

仅当文件名短于 200 个字符时才有效。

diff <(tar -tvf 1.tar | awk '{printf "%10s %200s %10s\n",$3,$6,$1}'|sort -k2) <(tar -tvf 2.tar|awk '{printf "%10s %200s %10s\n",$3,$6,$1}'|sort -k2)
于 2013-05-14T09:43:08.050 回答
2

tardiff是您要找的吗它是“一个简单的 perl 脚本”,“比较两个 tarball 的内容并报告它们之间发现的任何差异”。

于 2009-06-23T03:54:36.527 回答
2

还有diffoscope,它更通用,允许递归比较事物(包括各种格式)。

pip install diffoscope
于 2019-02-28T12:45:41.267 回答
1

只是把它扔在那里,因为上述解决方案都不能满足我的需要。

此函数获取与给定路径匹配的所有文件路径的 md5 哈希的 md5 哈希。如果哈希值相同,则文件层次结构和文件列表相同。

我知道它的性能不如其他产品,但它提供了我需要的确定性。

PATH_TO_CHECK="some/path"
for template in $(find build/ -name '*.tar'); do
    tar -xvf $template --to-command=md5sum | 
        grep $PATH_TO_CHECK -A 1 | 
        grep -v $PATH_TO_CHECK | 
        awk '{print $1}' | 
        md5sum | 
        awk "{print \"$template\",\$1}"
done

*注意:无效路径根本不返回任何内容。

于 2021-07-26T06:12:32.340 回答
1

我建议gtarsum,这是我用 Go 编写的,这意味着它将是一个自治的可执行文件(不需要 Python 或其他执行环境)。

go get github.com/VonC/gtarsum

它将读取一个 tar 文件,并且:

  • 按字母顺序对文件列表进行排序,
  • 为每个文件内容计算一个 SHA256,
  • 将这些哈希连接成一个巨大的字符串
  • 计算该字符串的 SHA256

结果是基于文件列表及其内容的 tar 文件的“全局哈希”。

它可以比较多个 tar 文件,如果相同则返回 0,否则返回 1。

于 2020-09-08T07:55:58.957 回答
0

如果不提取档案也不需要差异,请尝试diff-q选项:

diff -q 1.tar 2.tar

如果没有差异,这个安静的结果将是“1.tar 2.tar 不同”或什么都没有。

于 2013-05-09T14:38:29.083 回答
0

有一个名为archdiff的工具。它基本上是一个可以查看档案的 perl 脚本。

Takes two archives, or an archive and a directory and shows a summary of the
differences between them.
于 2014-04-18T07:50:24.337 回答
0

我有一个类似的问题,我用python解决了,这里是代码。ps:虽然这段代码是用来比较两个zipball的内容,但是和tarball类似,希望能帮到你

import zipfile
import os,md5
import hashlib
import shutil

def decompressZip(zipName, dirName):
    try:
        zipFile = zipfile.ZipFile(zipName, "r")
        fileNames = zipFile.namelist()
        for file in fileNames:
            zipFile.extract(file, dirName)
        zipFile.close()
        return fileNames
    except Exception,e:
        raise Exception,e

def md5sum(filename):
    f = open(filename,"rb")
    md5obj = hashlib.md5()
    md5obj.update(f.read())
    hash = md5obj.hexdigest()
    f.close()
    return str(hash).upper()

if __name__ == "__main__":
    oldFileList = decompressZip("./old.zip", "./oldDir")
    newFileList = decompressZip("./new.zip", "./newDir")

    oldDict = dict()
    newDict = dict()

    for oldFile in oldFileList:
        tmpOldFile = "./oldDir/" + oldFile
        if not os.path.isdir(tmpOldFile):
            oldFileMD5 = md5sum(tmpOldFile)
            oldDict[oldFile] = oldFileMD5

    for newFile in newFileList:
        tmpNewFile = "./newDir/" + newFile
        if not os.path.isdir(tmpNewFile):
            newFileMD5 = md5sum(tmpNewFile)
            newDict[newFile] = newFileMD5

    additionList = list()
    modifyList = list()

    for key in newDict:
        if not oldDict.has_key(key):
            additionList.append(key)
        else:
            newMD5 = newDict[key]
            oldMD5 = oldDict[key]
            if not newMD5 == oldMD5:
            modifyList.append(key)

    print "new file lis:%s" % additionList
    print "modified file list:%s" % modifyList

    shutil.rmtree("./oldDir")
    shutil.rmtree("./newDir")
于 2016-12-10T13:08:14.660 回答