【发布时间】:2015-05-25 21:52:37
【问题描述】:
我正在尝试比较两个目录,每个目录都有一些文件和一个子目录。有没有办法在这两个文件夹上运行 diff ,但不在子目录上运行它?我试过使用diff -x'*/' foo bar,以及几个带有反斜杠的变体来逃避它们,但没有骰子。
子目录的实际名称可以更改,这就是我不想指定确切名称模式的原因。
谢谢!
【问题讨论】:
标签: linux bash shell command-line diff
我正在尝试比较两个目录,每个目录都有一些文件和一个子目录。有没有办法在这两个文件夹上运行 diff ,但不在子目录上运行它?我试过使用diff -x'*/' foo bar,以及几个带有反斜杠的变体来逃避它们,但没有骰子。
子目录的实际名称可以更改,这就是我不想指定确切名称模式的原因。
谢谢!
【问题讨论】:
标签: linux bash shell command-line diff
如果您已经在比较两个特定目录,那么我假设您知道它们的名称。在这种情况下,您只需动态确定每个子目录中包含的子目录列表。
假设您在父目录中;你有这样的结构,你想区分foo和bar,但你想排除baz和quux:
+-- foo/
| |-- baz/
| |
| +-- file.txt
|
+-- bar/
|-- quux/
|
+-- file.txt
使用find:
find * -mindepth 1 -type d
在foo 和bar 中生成子目录列表:
foo/baz
bar/quux
此时您可以将其写入临时文件:
find * -mindepth 1 -type d > exclude.txt
然后使用diff 的-X 标志,它允许您指定包含要从差异中排除的模式的文件。
然而,这并不完全有效,因为您需要从每个结果中分割父目录名称。我们可以使用cut 来做到这一点:
find * -mindepth 1 -type d | cut -d'/' -f2 > exclude.txt
这会产生以下结果:
baz
quux
所以你现在可以使用:
diff -X exclude.txt foo bar
或者,如果您不想创建临时文件,可以将其作为单行:
diff -uX <(find * -mindepth 1 -type d | cut -d'/' -f2) foo bar
希望这会有所帮助:)
【讨论】:
如果您只是对目录名称执行diff,而不添加-r 选项,GNU diff 将报告不同的子目录名称,但不会重复区分它们的内容。
这在 GNU diff 手册中有详细记录:4 Comparing Directories。
如果你想过滤掉目录名,可以通过一个脚本来管道差异,该脚本查找以“Only”开头的行并忽略那些“:”之后的部分是目录的行姓名。 diff 的输出格式是可以合理预测的。易于解析的一件事是 content(差异)缩进了一个空格,允许将第一列用于 markup。
这是一个简单的 Perl 脚本,它依赖于 GNU diff 的 -N 选项的副作用来简化过滤(使用 3.0 版测试):
#!/usr/bin/perl -w
use strict;
die "usage: $0 sourcedir targetdir"
unless ( $#ARGV == 1 and -d $ARGV[0] and -d $ARGV[1] );
open FP, "diff -u -N \"" . $ARGV[0] . "\" \"" . $ARGV[1] . "\" |"
or die "diff: $!";
while (<FP>) {
print unless ( $_ =~ /^Com/ );
}
close FP;
1;
-N 选项告诉diff 假装比较的每一边都存在,因此它为 每个 子目录显示“公共子目录”。
【讨论】: