递归地比较目录,忽略所有二进制文件
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】:
结合使用find
和file
命令。这需要您对目录中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?以上是关于递归地比较目录,忽略所有二进制文件的主要内容,如果未能解决你的问题,请参考以下文章