it-swarm.cn

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

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

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

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

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

正如 “ diff”工具的正则表达式风格似乎缺乏? 中所建议的,我尝试了grep -G

grep -G '#.*' file

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

那么,应如何使用此选项?如何使diff跳过某些行(在我的情况下为注释)?请不要建议greping文件并比较临时文件。

56
Lekensteyn

根据Gilles的说法,_-I_选项仅在集内除_-I_之外没有其他匹配项时才忽略一行。在测试之前,我还没有完全理解它。

考试

我的测试涉及三个文件:
文件_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*_-匹配空格(制表符和空格)(如果有)
      • _(#|$)_匹配井号,或者匹配行尾
54
Lekensteyn

尝试:

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

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

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

我们可以阅读 diffutils 手册:

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

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

此处为armel 也很好地解释了此行为。

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

7
kenorb

在网上搜索后,我发现了另一种更好的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

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

3
syjust

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

  • 使用grep -v "^#" | cat -s生成未注释的版本,然后将其进行比较或...
  • 使用vim -d查看文件。语法高亮显示使得注释与非注释之间的差异非常明显。差异的差异突出显示,使您一眼就能看到哪些值或部分值已更改,这使它成为我的最爱。
1
Caleb

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

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

或者你可以做

sed -e '/^#.*/d' -e 's/#.*//g' | cat -s
0
Philomath