1.filecmp模块介绍

当我们进行代码审计或校验备份结果时,往往需要检查原始与目 标目录的文件一致性,Python的标准库已经自带了满足此需求的模块 filecmp。filecmp可以实现文件、目录、遍历子目录的差异对比功能。比 如报告中输出目标目录比原始多出的文件或子目录,即使文件同名也会 判断是否为同一个文件(内容级对比)等,Python 2.3或更高版本默认 自带filecmp模块,无需额外安装,下面进行详细介绍。

2.模块常用方法说明

filecmp提供了三个操作方法,分别为cmp(单文件对比)、 cmpfiles(多文件对比)、dircmp(目录对比),下面逐一进行介绍: ·

单文件对比:

采用filecmp.cmp(f1,f2[,shallow])方法,比较文 件名为f1和f2的文件,相同返回True,不相同返回False,shallow默认为 True,意思是只根据os.stat()方法返回的文件基本信息进行对比,比 如最后访问时间、修改时间、状态改变时间等,会忽略文件内容的对 比。当shallow为False时,则os.stat()与文件内容同时进行校验。

示例:比较单文件的差异

>>> import filecmp
>>> from filecmp import cmp
>>> cmp('/home/yhl/devpython/part2/nginx.conf.v1','/home/yhl/devpython/part2/nginx.conf.v2')
False
>>> cmp('/home/yhl/devpython/part2/nginx.conf.v1','/home/yhl/devpython/part2/nginx.conf.v0')
True

多文件对比:

采用filecmp.cmpfiles(dir1,dir2,common[, shallow])方法,对比dir1与dir2目录给定的文件清单。该方法返回文件 名的三个列表,分别为匹配、不匹配、错误。匹配为包含匹配的文件的 列表,不匹配反之,错误列表包括了目录不存在文件、不具备读权限或 其他原因导致的不能比较的文件清单

示例:dir1与dir2目录中指定文件清单对比。

两目录下文件的md5信息如下,其中f1、f2文件匹配;f3不匹配; f4、f5对应目录中不存在,无法比较。

创建测试文件:

[yhl@myhost part2]$ mkdir dir1
[yhl@myhost part2]$ mkdir dir2
[yhl@myhost part2]$ cd dir1
[yhl@myhost dir1]$ echo f1 >f1
[yhl@myhost dir1]$ echo f2 >f2
[yhl@myhost dir1]$ echo f3 >f3
[yhl@myhost dir1]$ echo f5 >f5
[yhl@myhost dir1]$ cd ../dir2
[yhl@myhost dir2]$ echo f1 >f1
[yhl@myhost dir2]$ echo f2 >f2
[yhl@myhost dir2]$ echo f03 >f3
[yhl@myhost dir2]$ echo f4 >f4

对比dir1和dir2目录下文件的md5

[yhl@myhost dir1]$ md5sum *
2b1abc6b6c5c0018851f9f8e6475563b f1
575c5638d60271457e54ab7d07309502 f2
3385b5d27d4c2923e9cde7ea53f28e2b f3
4c89aa650e394e642f6a84df6cdb08a4 f5
[yhl@myhost dir1]$ cd -
/home/yhl/devpython/part2/dir2
[yhl@myhost dir2]$ md5sum *
2b1abc6b6c5c0018851f9f8e6475563b f1
575c5638d60271457e54ab7d07309502 f2
287df2010a083579b709b63445a32cc3 f3
5f3022d3a5cbcbf30a75c33ea39b2622 f4

使用cmpfiles对比的结果如下,符合我们的预期。

f1、f2文件匹配;f3不匹配; f4、f5对应目录中不存在,无法比较。

>>> from filecmp import cmpfiles
>>> cmpfiles("/home/yhl/devpython/part2/dir1","/home/yhl/devpython/part2/dir2",['f1','f2','f3','f4','f5'])
(['f1', 'f2'], ['f3'], ['f4', 'f5'])

目录对比,通过dircmp(a,b[,ignore[,hide]])类创建一个目录 比较对象,其中a和b是参加比较的目录名。ignore代表文件名忽略的列 表,并默认为['RCS' , 'CVS' , 'tags'];hide代表隐藏的列表,默认为 [os.curdir,os.pardir]。dircmp类可以获得目录比较的详细信息,如只有 在a目录中包括的文件、a与b都存在的子目录、匹配的文件等,同时支 持递归。

dircmp提供了三个输出报告的方法: ·

report(),比较当前指定目录中的内容; ·

report_partial_closure(),比较当前指定目录及第一级子目录中 的内容; ·

report_full_closure(),递归比较所有指定目录的内容。

为输出更加详细的比较结果,dircmp类还提供了以下属性: ·

left,左目录,如类定义中的a; ·

right,右目录,如类定义中的b; ·

left_list,左目录中的文件及目录列表; ·

right_list,右目录中的文件及目录列表; ·

common,两边目录共同存在的文件或目录; ·

left_only,只在左目录中的文件或目录; ·

right_only,只在右目录中的文件或目录; ·

common_dirs,两边目录都存在的子目录; ·

common_files,两边目录都存在的子文件; ·

common_funny,两边目录都存在的子目录(不同目录类型或 os.stat()记录的错误); ·

same_files,匹配相同的文件; ·

diff_files,不匹配的文件; ·

funny_files,两边目录中都存在,但无法比较的文件; ·

subdirs,将common_dirs目录名映射到新的dircmp对象,格式为字 典类型。

示例:对比dir1与dir2的目录差异

通过调用dircmp()方法实现目录差异对比功能,同时输出目录 对比对象所有属性信息。

【simple3.py】

#!/usr/bin/python
#_*_coding:utf-8_*_
#****************************************************************#
# ScriptName: simple3.py
# Author: BenjaminYang
# Create Date: 2019-05-13 17:44
# Modify Author: BenjaminYang
# Modify Date: 2019-05-13 17:44
# Function:
#***************************************************************#
import filecmp
a="/home/yhl/devpython/part2/testfile/dir1" #定义左目录
b="/home/yhl/devpython/part2/testfile/dir2" #定义右目录
dir_obj=filecmp.dircmp(a,b,['test.py'])#目录比较 #输出对比结果数据报表,详细说明请参考filecmp类方法及属性信息
print '--------------report比较当前指定目录中的内容----------------'
dir_obj.report() #比较当前指定目录中的内容;
print '--------------report_partial_closure比较当前指定目录及第一级子目录中 的内容----------------'
dir_obj.report_partial_closure()#比较当前指定目录及第一级子目录中 的内容;
print '--------------report_full_closure递归比较所有指定目录的内容----------------'
dir_obj.report_full_closure() #递归比较所有指定目录的内容。
print '--------------left_list左目录中的文件及目录列表----------------'
print "left_list: "+ str(dir_obj.left_list) #左目录中的文件及目录表;
print '--------------right_list右目录中的文件及目录列表----------------'
print "right_list: "+ str(dir_obj.right_list) #右目录中的文件及目录列表;
print '--------------common两边目录共同存在的文件或目录----------------'
print "common: "+ str(dir_obj.common) #两边目录共同存在的文件或目录
print '--------------left_only只在左目录中的文件或目录----------------'
print "left_only: "+ str(dir_obj.left_only) #只在左目录中的文件或目录;
print '--------------right_only右目录中的文件及目录列表----------------'
print "right_only: "+ str(dir_obj.right_only) #只在右目录中的文件或目录;
print '--------------common_dirs两边目录都存在的子目录----------------'
print "common_dirs: "+ str(dir_obj.common_dirs) #两边目录都存在的子目录;
print '--------------common_files两边目录都存在的子文件----------------'
print "common_files: "+ str(dir_obj.common_files) #两边目录都存在的子文件;
print '--------------common_funny两边目录都存在的子目录(不同目录类型或os.stat()记录的错误----------------'
print "common_funny: "+ str(dir_obj.common_funny) #两边目录都存在的子目录(不同目录类型或os.stat()记录的错误);
print '--------------same_files匹配相同的文件----------------'
print "same_file: "+ str(dir_obj.same_files) #匹配相同的文件;
print '--------------diff_files不匹配的文件----------------'
print "diff_files: "+ str(dir_obj.diff_files) #不匹配的文件;
print '--------------funny_files#两边目录中都存在,但无法比较的文件----------------'
print "funny_files: "+ str(dir_obj.funny_files) #两边目录中都存在,但无法比较的文件

代码输出:

[yhl@myhost testfile]$ python simple3.py
--------------report比较当前指定目录中的内容----------------
diff /home/yhl/devpython/part2/testfile/dir1 /home/yhl/devpython/part2/testfile/dir2
Only in /home/yhl/devpython/part2/testfile/dir1 : ['f4']
Only in /home/yhl/devpython/part2/testfile/dir2 : ['aa', 'f5']
Identical files : ['f1', 'f2']
Differing files : ['f3']
Common subdirectories : ['a']
--------------report_partial_closure比较当前指定目录及第一级子目录中 的内容----------------
diff /home/yhl/devpython/part2/testfile/dir1 /home/yhl/devpython/part2/testfile/dir2
Only in /home/yhl/devpython/part2/testfile/dir1 : ['f4']
Only in /home/yhl/devpython/part2/testfile/dir2 : ['aa', 'f5']
Identical files : ['f1', 'f2']
Differing files : ['f3']
Common subdirectories : ['a'] diff /home/yhl/devpython/part2/testfile/dir1/a /home/yhl/devpython/part2/testfile/dir2/a
Identical files : ['a1']
Common subdirectories : ['b']
--------------report_full_closure递归比较所有指定目录的内容----------------
diff /home/yhl/devpython/part2/testfile/dir1 /home/yhl/devpython/part2/testfile/dir2
Only in /home/yhl/devpython/part2/testfile/dir1 : ['f4']
Only in /home/yhl/devpython/part2/testfile/dir2 : ['aa', 'f5']
Identical files : ['f1', 'f2']
Differing files : ['f3']
Common subdirectories : ['a'] diff /home/yhl/devpython/part2/testfile/dir1/a /home/yhl/devpython/part2/testfile/dir2/a
Identical files : ['a1']
Common subdirectories : ['b'] diff /home/yhl/devpython/part2/testfile/dir1/a/b /home/yhl/devpython/part2/testfile/dir2/a/b
Identical files : ['b1', 'b2', 'b3']
--------------left_list左目录中的文件及目录列表----------------
left_list: ['a', 'f1', 'f2', 'f3', 'f4']
--------------right_list右目录中的文件及目录列表----------------
right_list: ['a', 'aa', 'f1', 'f2', 'f3', 'f5']
--------------common两边目录共同存在的文件或目录----------------
common: ['a', 'f1', 'f2', 'f3']
--------------left_only只在左目录中的文件或目录----------------
left_only: ['f4']
--------------right_only右目录中的文件及目录列表----------------
right_only: ['aa', 'f5']
--------------common_dirs两边目录都存在的子目录----------------
common_dirs: ['a']
--------------common_files两边目录都存在的子文件----------------
common_files: ['f1', 'f2', 'f3']
--------------common_funny两边目录都存在的子目录(不同目录类型或os.stat()记录的错误----------------
common_funny: []
--------------same_files匹配相同的文件----------------
same_file: ['f1', 'f2']
--------------diff_files不匹配的文件----------------
diff_files: ['f3']
--------------funny_files#两边目录中都存在,但无法比较的文件----------------
funny_files: []

实践:校验源与备份目录差异

有时候我们无法确认备份目录与源目录文件是否保持一致,包括 源目录中的新文件或目录、更新文件或目录有无成功同步,定期进行校 验,没有成功则希望有针对性地进行补备份。本示例使用了filecmp模块 的left_only、diff_files方法递归获取源目录的更新项,再通过 shutil.copyfile、os.makedirs方法对更新项进行复制,最终保持一致状 态。详细源码如下:

【simple4.py】

#!/usr/bin/python
#_*_coding:utf-8_*_
#****************************************************************#
# ScriptName: simple4.py
# Author: BenjaminYang
# Create Date: 2019-05-14 17:48
# Modify Author: BenjaminYang
# Modify Date: 2019-05-14 17:48
# Function:
#***************************************************************#
import os, sys
import filecmp
import re
import shutil
holderlist=[] def compareme(dir1,dir2): #递归获取更新函数
dircomp=filecmp.dircmp(dir1,dir2)
only_in_one=dircomp.left_only #源目录新文件或目录
diff_in_one=dircomp.diff_files #不匹配文件,源目录文件已发生变化
dirpath=os.path.abspath(dir1) #定义源目录绝对路径
#将更新文件名或目录追加到holderlist
[holderlist.append(os.path.abspath(os.path.join(dir1,x))) for x in only_in_one]
[holderlist.append(os.path.abspath(os.path.join(dir1,x))) for x in diff_in_one]
if len(dircomp.common_dirs)>0: #判断是否存在相同的子目录,以便递归
for item in dircomp.common_dirs: #递归子目录
compareme(os.path.abspath(os.path.join(dir1,item)),\
os.path.abspath(os.path.join(dir2,item)))
return holderlist
def main():
if len(sys.argv)>2: #要求输入源目录与备份目录
dir1=sys.argv[1]
dir2=sys.argv[2]
else:
print "Usage: ",sys.argv[0], "datadir backupdir"
sys.exit()
source_files=compareme(dir1,dir2) #对比源目录与备份目录
dir1=os.path.abspath(dir1)
if not dir2.endswith('/'): dir2=dir2+'/' #备份目录路径加"/"符
dir2=os.path.abspath(dir2)
destination_files=[]
createdir_bool=False
for item in source_files: #遍历返回的差异文件或目录
destination_dir=re.sub(dir1,dir2,item)#将源目录差异路径清单对应替换成备份目录
destination_files.append(destination_dir)
if os.path.isdir(item): #如果差异路径为目录且不存在,则在备份目录中创建
if not os.path.exists(destination_dir):
os.makedirs(destination_dir)
createdir_bool=True #再次调用compareme函数标记
if createdir_bool: #重新调用compareme函数,重新遍历新创建目录的内容
destination_files=[]
source_files=[]
source_files=compareme(dir1,dir2) #调用compareme函数
for item in source_files: #获取源目录差异路径清单
destination_dir=re.sub(dir1,dir2,itme)
destination_files.append(destination_dir)
print "update item: "
print source_files #输出更新项列表清单
copy_pair=zip(source_files,destination_files)#将源目录与备份目录文件清单拆分成元组 for item in copy_pair:
if os.path.isfile(item[0]): #判断是否为文件,是则进行复制操作
shutil.copyfile(item[0],item[1]) if __name__=='__main__':
main()
[yhl@myhost testfile]$ python simple4.py dir1 dir2
update item:
['/home/yhl/devpython/part2/testfile/dir1/f4', '/home/yhl/devpython/part2/testfile/dir1/f3']
[yhl@myhost testfile]$ python simple4.py dir1 dir2
update item:
[] #再次运行时已经没有更新项了

python运维开发常用模块(5)文件目录对比模块filecmp的更多相关文章

  1. python运维开发常用模块(一)psutil

    1.模块简介 psutil是一个跨平台库(http://code.google.com/p/psutil/),能够轻 松实现获取系统运行的进程和系统利用率(包括CPU.内存.磁盘.网 络等)信息.它主 ...

  2. python运维开发常用模块(四)文件对比模块difflib

    1.difflib介绍 difflib作为 Python的标准库模块,无需安装,作用是对比文本之间的差异,且支持 输出可读性比较强的HTML文档,与Linux下的diff命令相似.我们可以 使用dif ...

  3. python运维开发常用模块(8)EXCEL操作模块XlsxWriter

    1.excel介绍 Excel是当今最流行的电子表格处理软件,支持丰富的计算函数及 图表,在系统运营方面广泛用于运营数据报表,比如业务质量.资源利 用.安全扫描等报表,同时也是应用系统常见的文件导出格 ...

  4. python运维开发常用模块(7)web探测模块pycurl

    1.模块介绍 pycurl(http://pycurl.sourceforge.net)是一个用C语言写的libcurl Python实现,功能非常强大,支持的操作协议有FTP.HTTP.HTTPS. ...

  5. python运维开发常用模块(6)发送电子邮件模块smtplib

    1.模块常用方法 SMTP类定义:smtplib.SMTP([host[,port[,local_hostname[, timeout]]]]),作为SMTP的构造函数,功能是与smtp服务器建立连接 ...

  6. python运维开发常用模块(三)DNS处理模块dnspython

    1.dnspython模块介绍: dnspython(http://www.dnspython.org/)是Python实现的一个DNS 工具包,它支持几乎所有的记录类型,可以用于查询.传输并动态更新 ...

  7. python运维开发常用模块(二)IPy

    1.安装 IP地址规划是网络设计中非常重要的一个环节,规划的好坏会直 接影响路由协议算法的效率,包括网络性能.可扩展性等方面,在这个 过程当中,免不了要计算大量的IP地址,包括网段.网络掩码.广播地 ...

  8. Python运维开发基础03-语法基础 【转】

    上节作业回顾(讲解+温习60分钟) #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen #只用变量和字符串+循环实现“用户登陆 ...

  9. Python运维开发基础01-语法基础【转】

    开篇导语 整个Python运维开发教学采用的是最新的3.5.2版,当遇到2.x和3.x版本的不同点时,会采取演示的方式,让同学们了解. 教学预计分为四大部分,Python开发基础,Python开发进阶 ...

随机推荐

  1. JDBC解耦案例

    原始JDBC连接 package jdbc; import org.junit.jupiter.api.Test; import java.sql.Connection; import java.sq ...

  2. Ubuntu 限制 指定端口和IP 访问

    限制端口和IP的时候 要注意别自己登陆不进去了,要不就惨了. 只允许指定的IP访问服务器的指定端口:22 只允许访问的ip: 192.168.1.1 192.168.1.2 192.168.1.3,禁 ...

  3. 咕咕咕-HLPP算法

    hlpp(欢乐婆婆)算法总结 突然发现咕了好久(X) emm先大概说一下,hlpp是针对网络流算法的一种复杂度更优的算法,基于预流推进(即模拟) 复杂度上界为 n2根号m 且跑不满 (所以学会了它,可 ...

  4. CTF必备技能丨Linux Pwn入门教程——PIE与bypass思路

    Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...

  5. Spring框架完全掌握(上)

    引言 前面我写了一篇关于Spring的快速入门,旨在帮助大家能够快速地了解和使用Spring.既然是快速入门,讲解的肯定只是一些比较泛的知识,那么对于Spring的一些深入内容,我决定将其分为上.下两 ...

  6. [b0015] python 归纳 (一)_python组织方式

    结论: xxx.yyyy yyyy 可以是 类.类对象.函数.变量 xxx 可以是 包.模块.类 代码: ref1.py # -*- coding: utf-8 -*- import os class ...

  7. elasticsearch 单节点出现unassigned_shards

    查看单节点Elasticsearch健康状态 使用head插件查看集群状态 从上面截图可以看出存在5个unassigned的分片,新建索引blog5的时候,分片数为5,副本数为1,新建之后集群状态成为 ...

  8. EM算法-完整推导

    前篇已经对EM过程,举了扔硬币和高斯分布等案例来直观认识了, 目标是参数估计, 分为 E-step 和 M-step, 不断循环, 直到收敛则求出了近似的估计参数, 不多说了, 本篇不说栗子, 直接来 ...

  9. vnc服务器和windows2012密钥

    [root@localhost ~]# vncserver #启动服务器 windows 2012 64位-server版本的密钥 Windows Server 2012 Standard 密钥:NB ...

  10. 16、基于状态的iptable+高级路由(重点)

    --   基于状态的iptables   如果按照tcp/ip来划分连接状态,有12种之多 但iptables里只有4种状态:ESTABLISHED.NEW.RELATED及INVALID   这两个 ...