Diff只输出文件名

我正在寻找运行一个Linux命令,将递归比较两个目录,并输出只有的文件名是什么不同。这包括在一个目录中而不在另一个目录中的任何内容,反之亦然,以及文本差异。

231017 次浏览

从diff手册页:

< p > -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

在我的linux系统上获得只是的文件名

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

如果你想获取一个文件列表,这些文件只在一个目录中,而不是它们的子目录,只有它们的文件名:

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 {}

您也可以使用rsync

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

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

要以编程方式创建一个新的或修改过的文件列表,我能想到的最佳解决方案是使用rsync排序uniq:

(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 &大小”,
  • -n“执行无更改的试运行”,以及
  • --out-format="%n"到“使用指定的格式输出更新”,这里的“%n”仅用于文件名

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

rsync -rvc --delete --size-only --dry-run source dir target dir

我有一本目录。

$ tree dir1
dir1
├── a
│   └── 1.txt
├── b
│   └── 2.txt
└── c
├── 3.txt
├── 4.txt
└── d
└── 5.txt


4 directories, 5 files

我有另一个目录。

$ tree dir2
dir2
├── a
│   └── 1.txt
├── b
└── c
├── 3.txt
├── 5.txt
└── d
└── 5.txt


4 directories, 4 files

我可以区分两个目录。

$ diff <(cd dir1; find . -type f | sort) <(cd dir2; find . -type f| sort)
--- /dev/fd/11  2022-01-21 20:27:15.000000000 +0900
+++ /dev/fd/12  2022-01-21 20:27:15.000000000 +0900
@@ -1,5 +1,4 @@
./a/1.txt
-./b/2.txt
./c/3.txt
-./c/4.txt
+./c/5.txt
./c/d/5.txt