【问题标题】:diff to output only the file namesdiff 只输出文件名
【发布时间】:2011-09-07 05:45:11
【问题描述】:

我希望运行一个 Linux 命令,该命令将递归地比较两个目录并仅输出不同的文件名。这包括存在于一个目录中而不存在于另一个目录中的任何内容(反之亦然),以及文本差异。

【问题讨论】:

    标签: linux command-line diff


    【解决方案1】:

    你也可以使用rsync

    rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out
    

    【讨论】:

    • --size-only 将丢失大小相同但内容不同的文件,例如old/version.txt "29a" new/version.txt "29b"。改用:rsync -ric --dry-run old/ new/ 其中“-i”参数允许通过rsync -ric --dry-run old/ new/ | cut -d" " -f 2直接获取文件列表
    • 如果您只是在寻找丢失的文件(尤其是跨网络共享),这非常棒,因为它不会比较内容。这帮助我找到了一些在迁移到新 NAS 时失败的文件。
    • 确保在 rsync 的命令行中指定的路径包含尾部斜杠。没有它们,这将无法正常工作,并且 rsync 可能只会枚举所有文件名!
    • 关于不检查内容的cmets。这有时是可取的,至少在第一次通过时是这样。
    • @OverZealous 是的,但是大小与字节不同的可能性很大。尽管如此,我还是会排除 --size-only 来检查全部内容。
    【解决方案2】:
    rsync -rvc --delete --size-only --dry-run source dir target dir
    

    【讨论】:

      【解决方案3】:

      如果您想获取仅位于一个目录中而不是其子目录且仅位于其文件名中的文件列表:

      diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'
      

      如果你想递归地列出所有不同的文件和目录,它们的完整路径:

      diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'
      

      这样您就可以对所有文件应用不同的命令。

      例如,我可以删除 dir1 而不是 dir2 中的所有文件和目录:

      diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}
      

      【讨论】:

        【解决方案4】:

        运行diff -qr old/ new/ 的方法有一个主要缺点:它可能会丢失新创建的目录中的文件。例如。在下面的示例中,文件data/pages/playground/playground.txt 不在diff -qr old/ new/ 的输出中,而目录data/pages/playground/ 是(在浏览器中搜索playground.txt 以快速比较)。我还发布了以下解决方案on Unix & Linux Stack Exchange,但我也将其复制在这里:

        要以编程方式创建新文件或修改文件的列表,我能想到的最佳解决方案是使用 rsyncsortuniq

        (rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
        

        让我用这个例子来解释一下:我们想比较两个 dokuwiki 版本,看看哪些文件被更改,哪些文件是新创建的。

        我们使用 wget 获取 tar 并将它们提取到目录 old/new/

        wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
        wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
        mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
        mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1
        

        以一种方式运行 rsync 可能会错过新创建的文件,因为 rsync 和 diff 的比较显示如下:

        rsync -rcn --out-format="%n" old/ new/
        

        产生以下输出:

        VERSION
        doku.php
        conf/mime.conf
        inc/auth.php
        inc/lang/no/lang.php
        lib/plugins/acl/remote.php
        lib/plugins/authplain/auth.php
        lib/plugins/usermanager/admin.php
        

        只在一个方向运行 rsync 会丢失新创建的文件,反之则会丢失已删除的文件,比较 diff 的输出:

        diff -qr old/ new/
        

        产生以下输出:

        Files old/VERSION and new/VERSION differ
        Files old/conf/mime.conf and new/conf/mime.conf differ
        Only in new/data/pages: playground
        Files old/doku.php and new/doku.php differ
        Files old/inc/auth.php and new/inc/auth.php differ
        Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
        Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
        Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
        Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ
        

        双向运行 rsync 并对输出进行排序以删除重复项显示目录 data/pages/playground/ 和文件 data/pages/playground/playground.txt 最初被遗漏:

        (rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
        

        产生以下输出:

        VERSION
        conf/mime.conf
        data/pages/playground/
        data/pages/playground/playground.txt
        doku.php
        inc/auth.php
        inc/lang/no/lang.php
        lib/plugins/acl/remote.php
        lib/plugins/authplain/auth.php
        lib/plugins/usermanager/admin.php
        

        rsync 使用这些参数运行:

        • -r“递归到目录”,
        • -c 还比较相同大小的文件,并且仅“基于校验和跳过,而不是 mod-time & size”,
        • -n“在不做任何更改的情况下进行试运行”,并且
        • --out-format="%n" 为“使用指定的格式输出更新”,此处为“%n”,仅用于文件名

        rsync 在两个方向上的输出(文件列表)使用sort 进行组合和排序,然后通过使用uniq 删除所有重复项来压缩此排序列表

        【讨论】:

        • 你不能向后运行它 (diff new/ old/) 看看哪些目录被删除了吗?
        • 在上面的示例中运行 diff -qr new/ old/ 并使用 dokuwiki tar 会产生与 diff -qr old/ new/ 相同的输出——即您会看到目录是新的/丢失的,但不是其中的文件
        【解决方案5】:

        来自差异手册页:

        -q  仅报告文件是否不同,而不是差异的详细信息。
        -r 比较目录时,递归比较找到的任何子目录。

        示例命令:

        diff -qr dir1 dir2
        

        示例输出(取决于语言环境):

        $ ls dir1 dir2
        dir1:
        same-file  different  only-1
        
        dir2:
        same-file  different  only-2
        $ diff -qr dir1 dir2
        Files dir1/different and dir2/different differ
        Only in dir1: only-1
        Only in dir2: only-2
        

        【讨论】:

        • 谢谢 - CentOS 7 中的 diff 手册页将 -q 描述为“仅在文件不同时报告”,这不如您写的那么清楚。
        • 这比较了文件的实际内容,这通常是人们想要的,但是,rsync 答案提供了只查看文件名和大小而不是内容的选项;这有时是可取的。
        • 也适用于 macOS。
        • 另外,可以在命令中包含-x PATTERN 以排除某些子目录。例如,diff -qr repo1 repo2 -x ".git" 将比较两个目录,但会排除其中包含“.git”的文件路径。
        【解决方案6】:

        在我的 linux 系统上获取 文件名

        diff -q /dir1 /dir2|cut -f2 -d' '
        

        【讨论】:

        • 我不会在我的 linux 系统上放置带空格的文件名。 ;)
        • 我并不是想把这归咎于你... ;-p 只是作为一个暗示...
        • 对我不起作用。我的目录结构如下audit-0.0.234/audit-data-warehouse-0.0.234/ audit-0.0.235/audit-data-warehouse-0.0.235/
        • diff -qrN /dir1 /dir2 | cut -f2 -d' ' 适合我!
        猜你喜欢
        • 2011-12-20
        • 2012-03-31
        • 2011-11-10
        • 2011-12-07
        • 2013-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多