Linux中diff命令的功能为逐行比较两个文本文件,列出其不同之处。它对给出的文件进行系统的检查,并显示出两个文件中所有不同的行。
而python中difflib 模块包含用来计算字符序列间不同并进行处理的工具。它在比较文本方面十分有效,同时还包含了利用若干公共差异格式来生成报告的函数。
下面来说明,如何使用diff命令。
文本比对命令(diff)
在 Windows 下,Beyond Compare是文件比较工具。主要用途是对比两个文件夹或者文件,并将差异以颜色标示。比较范围包括目录,文档内容等。
在Linux中。diff命令是以逐行的方式,比较文本文件的异同处。如果该命令指定进行目录的比较,则将会比较该目录中具有相同文件名的文件,而不会对其子目录文件进行任何比较操作。
diff命令的输出格式有三种
正常格式(normal diff)
上下文格式(context diff)
合并格式(unified diff)
语法:
diff(选项)(参数)
常用选项:
-a diff预设只会逐行比较文本文件;
-b 不检查空格字符的不同;
-c:显示全部内容,并标出不同之处;
-e 此参数的输出格式可用于ed的script文件;
-u 以合并的方式来显示文件内容的不同;
-w 忽略全部的空格字符;
-y 以并列的方式显示文件的异同之处;
参数:
文件1:指定要比较的第一个文件;
文件2:指定要比较的第二个文件。
我们现在来依次讲解。
正常格式
举个例子,现在有1个文件test1.c,里面内容如下:
#include
int main(int argc, char *argv[])
{
printf("hello world!\n");
return 0;
}
第二个文件:
#include
int main(int argc, char *argv[])
{
printf("hello Minger!\n");
return 0;
}
正常格式下我们无需加任何选项,直接如下比对就好:
第一行(6c6)是一个提示,用来说明变动位置。
它分成三个部分:前面的"6",表示test1.c的第6行有变化;中间的"c"表示变动的模式是内容改变(change),其他模式还有"增加"(a,代表addition)和"删除"(d,代表deletion);后面的"6",表示变动后变成test2.c的第6行。
第二行:< printf(“hello world!\n”);
表示test1.c文件中去除第6行的内容,其中小于号表示去除。
第三行:------
表示分隔线。
第四行:> printf(“hello Minger!\n”);
表示test2.c文件中增加第2行的内容,其中大于号表示增加。
上下文格式
上面我们看到正常格式下,信息是不是很少。导致我们无法快速定位所修改的地方,经常需要打开文件才知道修改细节。所以,为了给出更多的信息,引入了上下文格式。
它的使用方法是加入c参数(代表context)。例如:
diff -c file1 file2
我们还是使用上面的文件test1.c 和 test2.c,来看看效果。
从上面的信息来看,第1行和第2行表示修改前及修改后的文件及更新时间。
下面的*** 3,8 ****表示test1.c文件显示的从第3行开始到第8行为止的内容。
另外,文件内容的每一行最前面,还有一个标记位。如果为空,表示该行无变化;如果是感叹号(!),表示该行有改动;如果是减号(-),表示该行被删除;如果是加号(+),表示该行为新增。
后面几行的含义类似。表示显示变动后的文件,即test2.c
合并格式
从名字上我们就可以看出,这种格式就是上面介绍那两个格式的综合版,同时这种格式也是git diff所采用的格式。
它的使用方法是加入u参数(代表unified)。
diff -u file1 file2
来看看效果:
第1行和第2行表示修改前及修改后的文件及更新时间。
第二部分,变动的位置用两个@作为起首和结束
@@ -3,6 +3,6 @@
前面的"-3,6"分成三个部分:减号表示第一个文件(即test1.c),"3"表示第3行,“6"表示连续6行。合在一起,就表示下面是第一个文件从第3行开始的连续6行。同样的,”+3,6"表示变动后,成为第二个文件从第3行开始的连续6行。
除了以上三种格式外,还有另外一直更直观的方式——并排格式。这种显示格式的命令格式如下:
这种格式就是以并列的格式进行显示,也很直观明了。有个“|”符号,表示这行有更改。
好了,diff命令就简单说到这里了,想要更多了解diff,可以通过man 手册查看。
使用Python标准库difflib
difflib 模块包含一些用来计算和处理序列之间差异的工具。它对于比较文本尤其有用,其中包含的函数可以使用多种常用差异格式生成报告。
两个 字符串的差异对比
本示例通过使用difflib模块实现两个字符串的差异对比,然后以版本控制风格进行输出。
下面以 difflib_data.py 模块内的测试数据:
text1 = """This module provides classes and functions for comparing sequences.
It can be used for example, for comparing files,
and can produce difference information in various formats,
including HTML and context and unified diffs. For comparing directories and files,
see also, the filecmp module."""
text1_lines = text1.splitlines()
text2 = """This module provides classes and functions for comparing sequences.
It can be used for example, for comparing file,
and can produce difference information in various format,
including HTML and context and unified diff. For comparing directories and file,
see also, the filecmp module."""
text2_lines = text2.splitlines()
difflib_differ.py
#!/usr/local/bin/python38
import difflib
from difflib_data import *
d = difflib.Differ()
diff = d.compare(text1_lines, text2_lines)
print('\n'.join(diff))
在将文本传递给 compare() 之前将文本分解为一系列单独的行会生成比传入大字符串更可读的输出。
Differ 类适用于文本行序列并产生人类可读的 增量 ,或更改指令,包括各行内的差异。Differ 生成的默认输出类似于 Unix 下的 diff 命令行工具。它包括来自两个列表的原始输入值和标记数据,以指示进行了哪些更改。
以 - 为前缀的行在第一个序列中,但不在第二个序列中。
以 + 为前缀的行在第二个序列中,但不在第一个序列中。
如果某行之间的版本之间存在增量差异,则使用前缀为 ? 的额外行来突出显示新版本中的更改。如果一条线没有改变,则在左列上打印一个额外的空白区域,使其与可能存在差异的另一个输出对齐。
其他输出格式
虽然 Differ 类展示了所有的输入行,unified diff 仅包括修改过的行和一些上下文。unified_diff() 函数产生这种输出。
#!/usr/local/bin/python38
import difflib
from difflib_data import *
diff = difflib.unified_diff( text1_lines, text2_lines, lineterm='', )
print('\n'.join(diff))
lineterm 参数用于告诉 unified_diff() 跳过追加新行到它返回的控制行,因为输入行不包含它们。打印时,新行将添加到所有行。对于许多流行的版本控制工具的用户来说,输出看起来应该很熟悉。
使用 context_diff() 产生类似的可读输出。是不是看上去跟diff命令合并格式一个格式显示。这里就不多说介绍显示信息了。
参考:https://learnku.com/docs/pymotw/difflib-character-comparison/3363