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

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

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

如何diff跳过注释运行配置文件?注释行定义为:

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

跳过第一个要求的(最简单的)正则表达式是#.*.我尝试了GNU diff 3.0 的--ignore-matching-lines=RE( -I RE) 选项,但我无法让它与该 RE 一起工作。我也尝试过.*#.*.*\#.*没有运气。从字面上看,将行 ( Port 631) asRE不匹配任何内容,将 RE 放在斜杠之间也无济于事。

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

grep -G '#.*' file

这似乎与评论相符,但它不适用于diff -I '#.*' file1 file2.

那么,这个选项应该如何使用呢?我怎样才能diff跳过某些行(在我的例子中是注释)?请不要建议grep检查该文件并比较临时文件。

答案1

根据 Gilles 的说法,-I只有当该集合中除了 的匹配之外没有其他内容匹配时,该选项才会忽略一行-I。直到我测试后我才完全明白。

考试

我的测试涉及到三个文件:
Filetest1:

    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*- 匹配空白(制表符和空格)(如果有)
      • (#|$)匹配哈希标记,或者行尾

答案2

尝试:

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

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

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

我们可以读入diffutils手动的:

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

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

这种行为也得到了很好的解释阿梅尔在这里

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

答案3

在网上搜索后,我发现了一个类似于 Lekensteyn 的方法。

但我想使用diff输出作为 的输入patch,并grep -v更改格式,所以我不能。

也许这是一个改进:

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

它并不完美,但行号保留在补丁文件中。

但是,如果添加新行而不是注释行,则注释将导致修补时失败:

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 是进程替换生成的文件。 “+new line”和“-other text”之间的行是默认的空格字符,我们在 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

一个解决方案是不使用统一的 diff 格式;所以,没有-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

现在补丁文件可以工作了(但不能保证更复杂的情况)。

答案4

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

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

或者你可以做

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

相关内容