【问题标题】: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 年前的目录吗?

标签: bash shell diff binaryfiles


【解决方案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 给定的值处拆分字符串来创建数组
      猜你喜欢
      • 2013-11-18
      • 2013-12-13
      • 2011-01-03
      • 1970-01-01
      • 2016-02-15
      • 1970-01-01
      • 2013-08-18
      • 2017-09-05
      • 1970-01-01
      相关资源
      最近更新 更多