difflib作为python的标准库模块,无需安装,作用是对比文本之间的差异,且支持输出可读性比较强的HTML文档,与Linux下的diff命令类似。我们可以使用difflib对比代码、配置文件的差别,在版本控制方面是非常有用。
1、两个字符串的差异对比
1 #!/usr/bin/env python 2 #coding=utf-8 3 import difflib 4 5 #比对两个字符串中的不同点 6 text1 = "text1 hello world!" #定义字符串 7 text1_lines = text1.splitlines() #进行分隔,以便进行对比 8 text2 = "text2 Hello World." 9 text2_lines = text2.splitlines()10 11 a = difflib.Differ() #创建Differ()对象12 diff = a.compare(text1_lines,text2_lines) #采用compare方法对字符串进行比较13 print '\n'.join(list(diff))
实践对比Nginx配置文件差异
1 #!/usr/bin/env python 2 #coding=utf-8 3 4 import difflib 5 import sys 6 try: 7 textfile1 = sys.argv[1] #第一个配置文件路径参数 8 textfile2 = sys.argv[2] #第二个配置文件路径参数 9 10 except Exception,e: 11 print "Error:" + str(e)12 print "Usage: file_diff.py filename1 filename2"13 sys.exit()14 15 def readfile(filename): #文件读取分隔函数16 try:17 fileHandle = open (filename, 'rb')18 text = fileHandle.read().splitlines() #读取以后进行分隔19 fileHandle.close()20 return text21 except IOError as error:22 print ('Read file Error:' + str(error))23 sys.exit()24 25 if textfile1 == "" or textfile2 == "":26 print "Usage: file_diff.py filename1 filename2"27 sys.exit()28 29 text1_lines = readfile(textfile1) #调用readfile函数,获取分隔后的字符串30 text2_lines = readfile(textfile2)31 32 d = difflib.HtmlDiff() #创建HtmlDiff()类对象33 print d.make_file(text1_lines,text2_lines) #通过make_file方法输出HTML格式的对比结果34 35 运行如下代码:36 python sample.py nginx.conf.v1 nginx.conf.v2 > diff.html
2、文件与目录差异对比方法
filecmp提供了三个操作方法,分别是cmp(单文件对比)、cmpfiles(多文件对比)、dircmp(目录对比)
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 import os, sys 5 import filecmp 6 import re 7 import shutil 8 9 holderlist = []10 11 ##对应第一个步骤12 def compare_me(dir1, dir2): #递归获取更新项函数13 dircomp = filecmp.dircmp(dir1, dir2)14 only_in_one = dircomp.left_only #源目录新文件或目录15 diff_in_one = dircomp.diff_files #不匹配文件,源目录已发生变化16 dirpath = os.path.abspath(dir1) #定义源目录绝对路径17 18 #将更新文件名或者目录追加到holderlist19 [ holderlist.append(os.path.abspath(os.path.join(dir1, x))) for x in only_in_one ]20 [ holderlist.append(os.path.abspath(os.path.join(dir1, x))) for x in diff_in_one ]21 if len(dircomp.common_dirs) > 0:22 for item in dircomp.common_dirs:23 compare_me(os.path.abspath(os.path.join(dir1, item)), os.path.abspath(os.path.join(dir2, item)))24 return holderlist25 26 ##对应第二个步骤27 def main():28 if len(sys.argv) > 2: #要求输入源目录与备份目录29 dir1 = sys.argv[1]30 dir2 = sys.argv[2]31 else:32 print "Usage: ", sys.argv[0], "datadir backupdir"33 sys.exit()34 35 source_files = compare_me(dir1, dir2) #对比源目录与备份目录36 dir1 = os.path.abspath(dir1)37 if not dir2.endswith('/'): #备份目录路径加"/"符38 dir2 = dir2 + '/'39 dir2 = os.path.abspath(dir2)40 destination_files = []41 createdir_bool = False42 43 for item in source_files: #遍历返回的差异文件或目录清单44 destination_dir = re.sub(dir1, dir2, item) #将源目录差异路径清单对应替换成备份目录45 destination_files.append(destination_dir)46 if os.path.isdir(item): #如果差异路径为目录且不存在,则备份目录中创建47 if not os.path.exists(destination_dir):48 os.makedirs(destination_dir)49 createdir_bool = True #再次调用compareme函数标记50 51 ##对应第三个步骤 52 if createdir_bool: #重新调用compareme函数,重新遍历新创建目录的内容53 destination_files = []54 source_files = []55 source_files = compare_me(dir1, dir2) #调用compareme函数56 for item in source_files: #获取源目录差异路径清单,对应替换成备份目录57 destination_dir = re.sub(dir1, dir2, item)58 destination_files.append(destination_dir)59 60 ##对应第四个步骤61 print "update item: "62 print source_files #输出更新项列表清单63 copy_pair = zip(source_files, destination_files) #将源目录与备份目录文件清单拆分成元祖64 print "copy_pair is %s" % copy_pair65 for item in copy_pair:66 print "item is %s, %s" % (item[0], item[1])67 if os.path.isfile(item[0]): #判断是否为文件,是则进行复制操作68 shutil.copyfile(item[0], item[1])69 70 if __name__ == '__main__':71 main()