我有两个配置文件,一个是来自包管理器的原始配置文件,另一个是我自己修改的自定义配置文件。我添加了一些评论来描述行为。
如何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