递归地比较目录,忽略所有二进制文件

Posted

技术标签:

【中文标题】递归地比较目录,忽略所有二进制文件【英文标题】:diff a directory recursively, ignoring all binary files 【发布时间】:2011-10-06 08:31:26 【问题描述】:

在 Fedora Constantine 盒子上工作。我正在寻找diff 递归地检查两个目录以检查源更改。由于项目的设置(在我自己参与上述项目之前!sigh),目录包含源代码和二进制文件,以及大型二进制数据集。虽然 diff 最终会在这些目录上起作用,但如果我可以忽略二进制文件,可能需要 20 秒。

据我所知,diff 没有“忽略二进制文件”模式,但确实有一个忽略参数,它将忽略文件中的正则表达式 within。我不知道该写什么来忽略二进制文件,不管扩展名。

我正在使用以下命令,但它不会忽略二进制文件。有谁知道如何修改这个命令来做到这一点?

diff -rq dir1 dir2

【问题讨论】:

尝试使用cmp而不是diff,不会忽略二进制文件,但应该更快 eek。这是源代码控制的典型理由。如果你不使用它,你应该使用它。如果决定权不在你手中,你应该激烈争论。你的问题会随着正确的 git 设置而消失...... 哦,相信我。我知道。我正在做本科研究,但这并没有按照应有的方式进行设置。相信我。我知道。 CVS/SVN/GIT 会解决这个问题。知道还有什么比这更糟糕的吗?我被分配从事一个几乎没有文档的 Fortran 项目。该目录中有 8 个版本的项目,每个版本都有不同的 makefile(几乎 ;))做同样的事情。相信你,我正在尽我所能与我的监督争论。 @FredrikPihl I don't think cmp 支持目录。更不用说递归了。它支持 10 年前的目录吗? 【参考方案1】:

如果您项目中的二进制文件的名称遵循特定模式(*.o*.so、...),您可以将这些模式放在一个文件中并使用 -X 指定它(连字符 X)。

我的exclude_file的内容

*.o
*.so
*.git

命令:

diff -X exclude_file -r . other_tree > my_diff_file

更新:

-x 可以用来代替-X,在命令行而不是在文件中指定排除模式:

diff -r -x *.o -x *.so -x *.git dir1 dir2

【讨论】:

它是 -x 不是 -X。 @code_dweller 两者都存在:-x 用于在命令行中排除一个模式,而-X 表示包含所有要排除的模式的文件。 答案中给出的最后一个命令应该在星号周围加上引号,否则 shell 将根据 当前目录中存在的文件扩展它们(在调用 diff 之前)。因此,该命令应为diff -rx '*.o' -x '*.so' -x '*.git' dir1 dir2【参考方案2】:

我来这个(旧)问题是为了寻找类似的东西(与默认的 apache 安装相比,旧生产服务器上的配置文件)。遵循@fearlesstost 在 cmets 中的建议,git 足够轻巧且快速,可能比上述任何建议都更直接。 复制 version1 到新目录。然后做:

git init
git add .
git commit -m 'Version 1'

现在删除此目录中版本 1 中的所有文件,并将版本 2 复制到目录中。现在做:

git add .
git commit -m 'Version 2'
git show

这将向您显示第一次提交和第二次提交之间所有差异的 Git 版本。对于二进制文件,它只会说它们不同。或者,您可以为每个版本创建一个分支,并尝试使用 git 的合并工具将它们合并。

【讨论】:

【参考方案3】:

好吧,作为一种粗略的检查,您可以忽略匹配 /\0/ 的文件。

【讨论】:

问题是,它看起来不像 diff 甚至根本不支持忽略文件。 -x 标志可用于忽略文件。【参考方案4】:

有点作弊,但这是我用的:

diff -r dir1/ dir2/ | sed '/Binary\ files\ /d' >outputfile

这递归地比较 dir1 和 dir2,sed 删除二进制文件的行(以“二进制文件”开头),然后重定向到输出文件。

【讨论】:

@Serg 您可以使用-x 标志排除文件。试试diff -r -x '*.xml' dir1 dir2 另外,man diff 了解更多信息。 如果您在使用不同语言的系统上,请将Binary\ files\ 替换为您的语言中的相应单词。它应该是前一两个词。在德语中,它的Binärdateien\ @xdhmoore 感谢您的评论!添加到它,-x 也是可重复的,如果你想排除 multiple 模式。类似-x '*.ext1' -x '*.ext2' -x 'ext3' 使用sed 比仅使用grep -v 'Binary files' 有什么好处吗?【参考方案5】:

结合使用findfile 命令。这需要您对目录中file 命令的输出进行一些研究;下面我假设您要区分的文件报告为 ascii。或者,使用grep -v 过滤掉二进制文件。

#!/bin/bash

dir1=/path/to/first/folder
dir2=/path/to/second/folder

cd $dir1
files=$(find . -type f -print | xargs file | grep ASCII | cut -d: -f1)

for i in $files;
do
    echo diffing $i ---- $dir2/$i
    diff -q $i $dir2/$i
done

由于您可能知道大型二进制文件的名称,请将它们放在哈希数组中,并且仅当文件不在哈希中时才进行比较,如下所示:

#!/bin/bash

dir1=/path/to/first/directory
dir2=/path/to/second/directory

content_dir1=$(mktemp)
content_dir2=$(mktemp)

$(cd $dir1 && find . -type f -print > $content_dir1)
$(cd $dir2 && find . -type f -print > $content_dir2)

echo Files that only exist in one of the paths
echo -----------------------------------------
diff $content_dir1 $content_dir2    

#Files 2 Ignore
declare -A F2I
F2I=( [sqlite3]=1 [binfile2]=1 )

while read f;
do
    b=$(basename $f)
    if ! [[ $F2I[$b] ]]; then
        diff $dir1/$f $dir2/$f
    fi
done < $content_dir1

【讨论】:

【参考方案6】:

也许使用grep -I(相当于grep --binary-files=without-match)作为过滤器来排序二进制文件。

dir1='folder-1'
dir2='folder-2'
IFS=$'\n'
for file in $(grep -Ilsr -m 1 '.' "$dir1"); do
   diff -q "$file" "$file/$dir1/$dir2"
done

【讨论】:

这看起来很有希望。我会检查一下,让你知道它是怎么回事/如果它成功了,我会接受作为答案! 有人知道IFS=$'\n'的用途吗? 它是一个 bash 内部变量。在 tldp.org/LDP/abs/html/internalvariables.html 下查找 IFS 以了解其精确定义和行为。 @Zubin IFS 表示内部字段分隔符,用于通过在 IFS 给定的值处拆分字符串来创建数组 @Zubin:见When do I set IFS to a newline in Bash?

以上是关于递归地比较目录,忽略所有二进制文件的主要内容,如果未能解决你的问题,请参考以下文章

在颠覆中递归地忽略整个源代码树中的文件

Linux之ack命令

是否应将.gradle文件夹添加到版本控制?

源代码管理工具调查

如何最好地比较两个编译的二进制文件? [关闭]

二进制安装数据库