首页 > 代码库 > Python 之 filecmp

Python 之 filecmp

Python 之 filecmp

2017年7月12日

参考书籍:《Python自动化运维 ——技术与最佳实践》 作者:李天斯

1.什么是filecmp

filecmp作为python的标准库,无需安装,作用是对文件,目录,遍历子目录的差异对比功能,它是一个轻量级的工具,在对linux服务器备份文件检验时非常有用。

2.filecmp的简单使用

2.1 cmp的简单使用

用法:filecmp.cmp(file1,file2),如果file1和file2相同的话,则会返回true,否则返回false,这就称为比较单文件的差异。

2.1.1 copy一个文件备份两次

1 # cp /etc/vnc.conf ./
2 # cp /etc/vnc.conf ./vnc.conf.bak

2.1.2 编写python代码

 1 # cat lcmp.py
 2 
 3 #!/usr/bin/env python
 4 
 5 import sys
 6 
 7 import filecmp
 8 
 9 import os
10 
11 try:
12 
13     file1 = sys.argv[1]
14 
15     file2 = sys.argv[2]
16 
17 except:
18 
19     print ("Please follow the parameters")
20 
21     sys.exit()
22 
23 if os.path.isfile(file1) and os.path.isfile(file2) :
24 
25     if filecmp.cmp(file1,file2):
26 
27         print ("Match success")
28 
29     else :
30 
31         print ("Match failed")
32 
33 else:
34 
35     print ("Please check files")
36 
37     sys.exit()

2.1.2 执行脚本输出

1 # python lcmp.py vnc.conf vnc.conf.bak 
2 Match success

由上诉结果可以看出,文件是对比OK了的,现在修改vnc.conf.bak的内容,再执行脚本

2.1.3再次执行

1 # sed -i s/vnc/liwang.org/ vnc.conf.bak
2 # python lcmp.py vnc.conf vnc.conf.bak 
3 Match failed

比对文件不成功,则输出了Match failed ,则证明脚本是ok

2.2 cmpfiles的简单使用

用法:filecmp.cmpfiles(dir1,dir2,common[files...]),作用是对比dir1 和 dir2 目录的差异,该方法会返回三个list,分别是匹配,不匹配,错误。

2.2.1 复制文件

1 # mkdir -p dir1 dir2
2 # cp lcmp.py vnc.conf vnc.conf.bak dir1/
3 # cp lcmp.py vnc.conf dir2/

2.2.2 编写python代码

 1 # cat lcmpfiles.py
 2 
 3 #!/usr/bin/env python
 4 
 5 import os
 6 
 7 import filecmp
 8 
 9 import sys
10 
11 dir1 = input("Please enter a folder to match:")
12 
13 dir2 = input("Please enter a folder to match:")
14 
15 files = []
16 
17 while True:
18 
19     local_files = input("Please enter the file to compare:[n/N Exit the input]")
20 
21     if local_files == N or local_files == n:
22 
23         break
24 
25     elif local_files == ‘‘:
26 
27         continue
28 
29     else :
30 
31         files.append(local_files)
32 
33 try:
34 
35     os.path.exists(dir1)
36 
37     os.path.exists(dir2)
38 
39 except:
40 
41     print ("Pleae check the folder.")
42 
43     sys.exit()
44 
45 #print (filecmp.cmpfiles(dir1,dir2,files)[0])
46 
47 print ("It‘s file match:",filecmp.cmpfiles(dir1,dir2,files)[0])
48 
49 print ("The file does not match:",filecmp.cmpfiles(dir1,dir2,files)[1])
50 
51 print ("File does not exists:",filecmp.cmpfiles(dir1,dir2,files)[2])

2.2.3 python3执行脚本(因为使用了input)

 1 # python3 lcmpfiles.py 
 2 Please enter a folder to match:dir1
 3 Please enter a folder to match:dir2
 4 Please enter the file to compare:[n/N Exit the input]lcmp.py
 5 Please enter the file to compare:[n/N Exit the input]vnc.conf
 6 Please enter the file to compare:[n/N Exit the input]vnc.conf.bak
 7 Please enter the file to compare:[n/N Exit the input]n
 8 Its file match: [lcmp.py, vnc.conf]
 9 The file does not match: []
10 File does not exists: [vnc.conf.bak]

可以看出,lcmp.py 和 vnc.conf 在dir1 和dr2都有,且文件内容相同,而vnc.conf.bak在dir1有,dir没有,故输出,文件匹配:lcmp.py和vnc.conf ,文件不存在:vnc.conf.bak,文件不相同:无

2.2 dircmp的简单使用

语法:dircmp(a,b,[,ignore[,hide]]) 其中a,b是文件名,ignore是可以忽略的列表,hide代表隐藏列表,dircmp可以获得目录比较详细的信息,同时还支持递归。

dircmp提供了三个输出方法:

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

report_full_closure() 递归比较所有指定文件的内容

2.2.1 模拟环境

1 # ls dir1/ dir2/
2 dir1/:
3 hosts  ld.so.conf  sysconfig
4 
5 dir2/:
6 hosts  ld.so.conf  sysconfig

其中,sysconfig 是一个目录 hosts ld.so.conf都是文件,hosts内容不一致 sysconfig中的文件也不一样

2.2.2 编写python代码

2.2.2.1 dircmp.report()

 1 # cat simple_filecmp.py
 2 
 3 #!/usr/bin/env python
 4 
 5 import filecmp
 6 
 7 dir1 = "/root/python/d_2_filecmp/cmp/dir2"
 8 
 9 dir2 = "/root/python/d_2_filecmp/cmp/dir1"
10 
11 dirobj = filecmp.dircmp(dir1,dir2)
12 
13 print (dirobj.report()) 

2.2.2.2 执行脚本

1 # python simple_filecmp.py 
2 diff /root/python/d_2_filecmp/cmp/dir2 /root/python/d_2_filecmp/cmp/dir1
3 Identical files : [ld.so.conf]
4 Differing files : [hosts]
5 Common subdirectories : [sysconfig]
6 None
7 [root@localhost cmp]# cat simple_filecmp.py 

由上面的结果,我们可以看出,report只能比对脚本的首层目录,而无法对子文件夹下的目录进行匹配

2.2.2.3 report_full_closure()

 1 # cat simple_filecmp_2.py
 2 
 3 #!/usr/bin/env python
 4 
 5 import filecmp
 6 
 7 dir1 = "/root/python/d_2_filecmp/cmp/dir1/"
 8 
 9 dir2 = "/root/python/d_2_filecmp/cmp/dir2/"
10 
11 dirobj = filecmp.dircmp(dir1,dir2)
12 
13 print (dirobj.report_full_closure())

2.2.2.4 执行脚本

1 diff /root/python/d_2_filecmp/cmp/dir1/ /root/python/d_2_filecmp/cmp/dir2/
2 Identical files : [ld.so.conf]
3 Differing files : [hosts]
4 Common subdirectories : [sysconfig]
5 
6 diff/root/python/d_2_filecmp/cmp/dir1/sysconfig /root/python/d_2_filecmp/cmp/dir2/sysconfig
7 ......

由此可见差别report()report_full_closure()的差别在于

3.filecmp案例

3.1 需求

需求:1.备份etc 文件夹下所有的内容,并且保持实时备份,如果有新的文件,则copy至备份文件中,如果有新的,则update

3.2 流程图

3.2.1 初步流程图:

 技术分享

3.2.2 对比文件差异流程图

技术分享

3.3 代码编写:

3.3.1 补充知识:

dircmp.left_only

只在左边出现的文件

 1 # cat simple_filecmp_3.py
 2 
 3 #!/usr/bin/env python
 4 
 5 import filecmp
 6 
 7 dir1 = "/root/python/d_2_filecmp/cmp/dir1/"
 8 
 9 dir2 = "/root/python/d_2_filecmp/cmp/dir2/"
10 
11 dirobj = filecmp.dircmp(dir1,dir2)
12 
13 print (dirobj.diff_files)

执行结果

1 # ls dir1 dir2/
2 dir1:
3 hosts  ld.so.conf  sysconfig  teacher
4 
5 dir2/:
6 hosts  ld.so.conf  sysconfig
7 [root@localhost cmp]# python simple_filecmp_3.py 
8 [teacher]

由上诉可见,teacher只出现在dir1,则会被抓取出来,所谓的leftright是相对于filecmp.dircmp而言的

dircmp.diff_files

返回不能匹配额文件

 1 # cat simple_filecmp_3.py
 2 
 3 #!/usr/bin/env python
 4 
 5 import filecmp
 6 
 7 dir1 = "/root/python/d_2_filecmp/cmp/dir1/"
 8 
 9 dir2 = "/root/python/d_2_filecmp/cmp/dir2/"
10 
11 dirobj = filecmp.dircmp(dir1,dir2)
12 
13 print (dirobj.diff_files)
14 
15 #print (dirobj.left_only)

执行结果

1 [root@localhost cmp]# ls dir1 dir2
2 dir1:
3 hosts  ld.so.conf  sysconfig  teacher
4 
5 dir2:
6 hosts  ld.so.conf  sysconfig
7 [root@localhost cmp]# python simple_filecmp_3.py 
8 [hosts]
9 [root@localhost cmp]# 

之前我们修改过hosts的文件,文件内容已经不一致,现在已经被抓取出来了

3.3.2 编写自动备份脚本

 1 # cat d_7_12_filecmp.py 
 2 #!/usr/bin/env python
 3 
 4 import filecmp
 5 import os
 6 import sys
 7 import shutil
 8 
 9 source_files = "/root/python/d_2_filecmp/dir1"
10 target_files = "/root/python/d_2_filecmp/dir2"
11 
12 def check_common_dirs(source_files,target_files):
13     dirsobj = filecmp.dircmp(source_files , target_files)
14 
15     common_dirs_list = dirsobj.common_dirs
16     
17     for common_line in common_dirs_list :
18         files_contrast(/+source_files+/+common_line,/+target_files+/+common_line)
19 
20 def files_contrast(dir1,dir2) :
21 
22     dirobj = filecmp.dircmp(dir1,dir2)
23 
24     no_exists_files = dirobj.left_only
25     no_diff_files = dirobj.diff_files
26 
27     for exists_files in no_exists_files :
28         
29         if os.path.isfile(exists_files) :
30             shutil.copyfile (/+dir1+/+exists_files , /+dir2+/+exists_files)
31         else :
32             print ("%s is dirctory" %(exists_files))
33             os.makedirs(/+dir2+/+exists_files)
34             print ("%s is mkdirs" %(/+target_files+/+exists_files))
35             
36             try :
37                 print ("values : %s %s" %(/+dir1+/+exists_files , /+dir2+/+exists_files))
38                 files_contrast(/+dir1+/+exists_files , /+dir2+/+exists_files)
39             except :
40                 return 
41 
42     for diff_files in no_diff_files :
43         if os.path.isfile(diff_files) :
44             os.remove(/+dir2+/+diff_files)
45             shutil.copyfile (/+dir1+/+diff_files , /+dir2+/+diff_files)
46 
47 if os.path.exists(source_files) :
48 
49     if os.path.exists(target_files) == "False" :
50         os.makedirs(target_files)
51     
52     files_contrast(source_files,target_files)    
53     check_common_dirs(source_files,target_files)
54 
55 else :
56     print ("Soure files no exists")
57     sys.exit()

3.4 执行脚本输出

3.4.1 查看文件

可知 dir2下没有任何文件

 1 # tree dir1/ dir2/
 2 dir1/
 3 ├── 123
 4 │   └── 123456
 5 ├── 4556
 6 │   └── 789
 7 │       └── d
 8 ├── lcmp.py
 9 ├── vnc.conf
10 └── vnc.conf.bak
11 dir2/
12 
13 3 directories, 5 files 

3.4.2 执行脚本

 1 root@localhost d_2_filecmp]# python d_7_12_filecmp.py 
 2 4556 is dirctory
 3 //root/python/d_2_filecmp/dir2/4556 is mkdirs
 4 values : //root/python/d_2_filecmp/dir1/4556 //root/python/d_2_filecmp/dir2/4556
 5 789 is dirctory
 6 //root/python/d_2_filecmp/dir2/789 is mkdirs
 7 values : ///root/python/d_2_filecmp/dir1/4556/789 ///root/python/d_2_filecmp/dir2/4556/789
 8 d is dirctory
 9 //root/python/d_2_filecmp/dir2/d is mkdirs
10 values : ////root/python/d_2_filecmp/dir1/4556/789/d ////root/python/d_2_filecmp/dir2/4556/789/d
11 123 is dirctory
12 //root/python/d_2_filecmp/dir2/123 is mkdirs
13 values : //root/python/d_2_filecmp/dir1/123 //root/python/d_2_filecmp/dir2/123
14 123456 is dirctory
15 //root/python/d_2_filecmp/dir2/123456 is mkdirs
16 values : ///root/python/d_2_filecmp/dir1/123/123456 ///root/python/d_2_filecmp/dir2/123/123456

可以看出,备份的信息,前面的多个/可以不必理会,linux只识别一个/

3.4.3 查看备份效果

 1 # tree dir1/ dir2/
 2 dir1/
 3 ├── 123
 4 │   └── 123456
 5 ├── 4556
 6 │   └── 789
 7 │       └── d
 8 ├── lcmp.py
 9 ├── vnc.conf
10 └── vnc.conf.bak
11 dir2/
12 ├── 123
13 │   └── 123456
14 ├── 4556
15 │   └── 789
16 │       └── d
17 ├── lcmp.py
18 ├── vnc.conf
19 └── vnc.conf.bak
20 
21 8 directories, 8 files

由上,可知,备份完全成功,针对于定时执行python脚本,可以将脚本写入crontab中,开启定时任务即可。

Python 之 filecmp