如何区分忽略注释的文件(以#开头的行)?


55

我有两个配置文件,一个是来自软件包管理器的原始文件,另一个是我自己修改的自定义文件。我添加了一些注释来描述行为。

如何diff在配置文件上运行而跳过注释?带注释的行由以下方式定义:

  • 可选的前导空格(制表符和空格)
  • 井号(#
  • 其他任何字符

跳过第一个要求的(最简单)正则表达式将是#.*。我尝试了GNU diff 3.0 的--ignore-matching-lines=RE-I RE)选项,但无法在RE中使用它。我也尝试过.*#.*.*\#.*没有运气。从字面上看,将(Port 631)放在RE任何地方都不匹配,将RE放在斜线之间也无济于事。

“ diff”工具中所建议的那样,似乎缺少正则表达式?,我尝试过grep -G

grep -G '#.*' file

这似乎与注释匹配,但不适用于diff -I '#.*' file1 file2

那么,该选项应如何使用?如何diff跳过某些行(在我的情况下为评论)?请不要建议grep文件和比较临时文件。


12
-I仅当块的所有行都与regexp匹配时,该选项才会使其忽略。因此,您可以通过这种方式忽略仅注释更改,但不能忽略接近非注释更改的注释更改。
吉尔(Gilles)“所以,别再邪恶了”,

@吉尔斯:谢谢,现在我明白了为什么diff -I表现不如预期。我用一个示例更新了我的答案,该示例为我澄清了这种行为。
Lekensteyn 2011年

Answers:


49

根据Gilles的说法,-I如果该集合中除的匹配项之外没有其他匹配项,则该选项仅忽略一行-I。在测试之前,我还没有完全理解它。

考试

我的测试涉及三个文件:
File test1

    text

档案test2

    text
    #comment

档案test3

    changed text
    #comment

命令:

$ # comparing files with comment-only changes
$ diff -u -I '#.*' test{1,2}
$ # comparing files with both comment and regular changes
$ diff -u -I '#.*' test{2,3}
--- test2       2011-07-20 16:38:59.717701430 +0200
+++ test3       2011-07-20 16:39:10.187701435 +0200
@@ -1,2 +1,2 @@
-text
+changed text
 #comment

替代方式

由于到目前为止尚无答案来解释如何-I正确使用该选项,因此我将提供一种在bash shell中有效的替代方法:

diff -u -B <(grep -vE '^\s*(#|$)' test1)  <(grep -vE '^\s*(#|$)' test2)
  • diff -u -统一差异
    • -B -忽略空白行
  • <(command)-称为流程替换的bash功能,它将为命令打开文件描述符,这消除了对临时文件的需要
  • grep -用于打印与图案匹配的行(不)的命令
    • -v -显示不匹配的行
    • E -使用扩展的正则表达式
    • '^\s*(#|$)' -匹配注释和空行的正则表达式
      • ^ -匹配一行的开头
      • \s* -匹配空格(制表符和空格)(如果有)
      • (#|$) 匹配哈希标记,或者匹配行尾

6

尝试:

diff -b -I '^#' -I '^ #' file1 file2

请注意,正则表达式必须匹配两个文件中的相应行,并且匹配大块中每个更改的行才能正常工作,否则它仍会显示出差异。

使用单引号来保护模式以防止shell扩展,并转义保留正则表达式的字符(例如括号)。

我们可以阅读diffutils手册:

但是,-I如果块中每条更改的行(每次插入和每次删除)都与正则表达式匹配,则仅忽略包含正则表达式的行的插入或删除。

换句话说,对于每个不可忽略的更改,diff在其附近打印完整的更改集,包括可忽略的更改。您可以使用多个-I选项来指定多个正则表达式,以便忽略的行。diff尝试将每行与每个正则表达式匹配,从给定的最后一个开始。

Armel在这里也很好地解释了这种行为。

相关:如何执行忽略所有注释的差异?


2

在网上搜索后,我发现了另一种更好的Lekensteyn方法。

但是我想使用dif输出作为补丁...,这是有问题的,因为“ grep -v”会保留行号。

因此,我打算改进此命令行:

diff -u -B <(sed 's/^[[:blank:]]*#.*$/ /' file1)  <(sed 's/^[[:blank:]]*#.*$/ /' file2)

这不是完美的方法,但是行号保存在补丁文件中。

但是,如果添加了新行而不是注释行,则在修补时,注释将产生Hunk FAILED,如下所示。

File test1:
  text
  #comment
  other text
File test2:
  text
  new line here
  #comment changed
  other text changed

现在测试我们的命令

$ echo -e "#!/usr/bin/sed -f\ns/^[[:blank:]]*#.*$/ /" > outcom.sed
$ echo "diff -u -B <(./outcom.sed \$1)  <(./outcom.sed \$2)" > mydiff.sh
$ chmod +x mydiff.sh outcom.sed
$ ./mydiff.sh file1 file2 > file.dif
$ cat file.dif
--- /dev/fd/63  2014-08-23 10:05:08.000000000 +0200
+++ /dev/fd/62  2014-08-23 10:05:08.000000000 +0200
@@ -1,2 +1,3 @@
 text
+new line

-other text
+other text changed

/ dev / fd / 62和/ dev / fd / 63是通过进程替换生成的文件。“ +换行”和“-其他文本”之间的行是我们sed表达式中定义的用于替换注释的默认空格字符。

现在,当我们应用此补丁时会发生什么:

$ patch -p0 file1 < file.dif 
patching file file1
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file file1.rej

解决方案是不使用不带-u的统一差异格式

$ echo "diff -B <(./outcom.sed \$1)  <(./outcom.sed \$2)" > mydiff.sh
$ ./mydiff.sh file1 file2 > file.dif
$ cat file.dif
1a2
> new line
3c4
< other text
---
> other text changed
$ patch -p0 file1 < file.dif 
patching file file1
$ cat file1
text
new line
#comment
other text changed

现在补丁文件的工作文件(不保证结果非常复杂的差异过程)。


由于上下文差异,您的统一差异无法应用。您可以diff -U0 one two用来禁用上下文。为了打补丁,有很多工具可能会更适合,例如kdiff3。
Lekensteyn

感谢您-U0选择禁用上下文。注意:kdiff3是图形工具。我需要自动工具来管理git merge属性。
syjust 2014年

vimdiff支持三向合并,可能值得一看。
Lekensteyn 2014年

更准确地说,我需要一个脚本工具来自动执行带有sql脚本中的排除项的git merge过程。kdiff3和vimdiff是交互工具,在我的情况下不可用。
syjust 2014年

1

我通常通过以下任一方法来忽略这种混乱情况:

  • 使用grep -v "^#" | cat -s并生成非注释版本,或将其与...
  • 使用vim -d看文件。突出显示语法可以使注释与非注释差异变得非常明显。差异的差异突出显示,使您一眼就能看到哪些值或部分值已更改,这使它成为我的最爱。

0

这是我用来删除所有注释行的方法,甚至包括以制表符或空格开头的注释行以及空白行:

egrep -v "^$|^[[:space:]]*#" /path/to/file

或者你可以做

sed -e '/^#.*/d' -e 's/#.*//g' | cat -s
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.