今天我们来看一下自动化开发过程中经常用到的两个模块,os和shutil模块的使用;
一、使用OS.path进行路径和文件管理
In [8]: import os In [9]: os.getcwd() Out[9]: '/data/python' In [12]: os.listdir('/data/python') Out[12]: ['result.html', 'simple.html', 'output', 'jinja2_test1.py', 'data.txt', 'jinja2_test2.py', 'out.txt', 'templates', 'server_config.ini']
1.拆分路径
os.path模块用来对文件和路径进行管理,显然,它会包含很多拆分路径的函数os.path模块中与拆分路径相关的函数有:
split:返回元组,包含文件的路径文件名;
dirname:返回文件的路径;
basename:返回文件的文件
splitext:返回个除去文件扩展名的部分和扩名的二元组
In [13]: import os In [14]: path='/data/python/data.txt' In [15]: os.path.split(path) Out[15]: ('/data/python', 'data.txt') In [16]: os.path.dirname(path) Out[16]: '/data/python' In [17]: os.path.basename(path) Out[17]: 'data.txt' In [18]: os.path.splitext(path) Out[18]: ('/data/python/data', '.txt') In [19]: os.path.splitdrive(path) Out[19]: ('', '/data/python/data.txt')
2.构建路径
Python工程师可以使用os.path块方便地拆分路,相应的,os.path模块包含了用以构建路径的函数其中最常用的便是expanduser、abspath、join函数
expanduser:展开用户的HOME,如~、~username;
abspath:得到文件或路径的绝对路径;
join:根据不同的操作系统平台,使用不同的路分隔符拼
In [21]: os.path.expanduser('~') Out[21]: '/root' In [22]: os.path.expanduser('~mysql') Out[22]: '/home/mysql' In [23]: os.path.expanduser('~wjq/test') Out[23]: '~wjq/test' In [24]: os.path.expanduser('~/wjq/test') Out[24]: '/root/wjq/test' In [25]: os.path.abspath('.') Out[25]: '/data/python' In [26]: os.path.abspath('../') Out[26]: '/data' In [27]: os.path.abspath('~/wjq/test/a.py') Out[27]: '/data/python/~/wjq/test/a.py' In [28]: os.path.abspath('/wjq/test/a.py') Out[28]: '/wjq/test/a.py' In [29]: os.path.abspath('./wjq/test/a.py') Out[29]: '/data/python/wjq/test/a.py' In [30]: os.path.join('~','wjq','test','a.py') Out[30]: '~/wjq/test/a.py' In [32]: os.path.join(os.path.expanduser('~'),'wjq','b.py') Out[32]: '/root/wjq/b.py'
3.获取文件属性
os.path模块也包含了若干函数用来获取文件的属性包括文件的创建时间、修改时间、文件大小等
getatime() 获取文件的访问时间
getmtime() 获取文件的修改时间
getctime() 获取文件的建时间
getsize() 获取文件的大小
4.判断文件类型
os.path模块也提供了若干函数用来判断路径是否存在,以及路径所指文件的类型,这些判断类函数般以“is”开头,且返回Boolean型结果os.path模块提供的判断类函数包括exists参数
path所指向的路径是否存在
isfile参数path所指向的路存在,并且是个文件;
isdir参数path所指向的路径存在,并且是一个文件夹;
islink参数path所指向的路径存在,并且是个链接;
ismount参数path所指向的路径存在,并且是个挂载点
1) 获取/data/python下所有的文件列表:
In [3]: [item for item in os.listdir(os.path.expanduser('/data/python')) if os.path.isfile(item)] Out[3]: ['result.html', 'simple.html', 'jinja2_test1.py', 'test.py', 'data.txt', 'jinja2_test2.py', 'out.txt', 'server_config.ini']
2)获取/data/python目录下所有的目录列表:
In [4]: [item for item in os.listdir(os.path.expanduser('/data/python')) if os.path.isdir(item)] Out[4]: ['output', 'templates']
3)获取/data/python目录下所有目录的目录名到绝对路之间的字典
In [6]: {item: os.path.realpath(item) for item in os.listdir(os.path.expanduser('/data/python')) if os.path.isdir(item)} Out[6]: {'output': '/data/python/output', 'templates': '/data/python/templates'}
4)获取当前用户home目录下所有文件到文件大小之间的字典:
In [8]: {item: os.path.getsize(item) for item in os.listdir(os.path.expanduser('/data/python')) if os.path.isfile(item)} Out[8]: {'data.txt': 687, 'jinja2_test1.py': 653, 'jinja2_test2.py': 1218, 'out.txt': 683, 'result.html': 432, 'server_config.ini': 99, 'simple.html': 448, 'test.py': 269}
二、使用OS模块管理文件和目录
OS模块封装了操作系统的API程师可以使用统的接口编平台程序OS模块中有大量的函数,我们这里介绍与文件处理相关的些函数前面已经介绍了getcwd函数,该函数用来获取前目录,与之相关的chdir函数,该函数用来修改当前目录如下所示:
In [9]: os.getcwd() Out[9]: '/data/python' In [10]: os.chdir('/data') In [11]: os.getcwd() Out[11]: '/data'
OS模块也包含了文件和目的操作函数,包括创录、删除目录、删除文件、重命名文件等。
unlink/remove :删除path路径所指向的文件;
rmdir:删path路径所指向的文件夹,该文件必须为空,否则会报错;
mkdir:创建一个文件夹
rename:重命名文件或文件夹。
下面的代码演示了使用OS模块进行模块和文件管理的用法:
In [4]: import os In [5]: os.listdir('.') Out[5]: ['tmpdir', 'b.txt', 'tmpdir2', '2.png', '1.jpg', 'a.txt'] In [6]: os.listdir('./tmpdir') Out[6]: ['c.txt'] In [7]: os.listdir('./tmpdir2') Out[7]: [] In [8]: os.remove('1.jpg') In [9]: os.unlink('2.png') In [10]: ls a.txt b.txt tmpdir/ tmpdir2/ In [11]: os.rmdir('tmpdir2/') In [12]: os.rmdir('tmpdir') --------------------------------------------------------------------------- OSError Traceback (most recent call last) in () ----> 1 os.rmdir('tmpdir') OSError: [Errno 39] Directory not empty: 'tmpdir' In [13]: os.mkdir('testdir') In [14]: ls a.txt b.txt testdir/ tmpdir/ In [15]: os.rename('a.txt','test.txt') In [16]: ls b.txt testdir/ test.txt tmpdir/
OS模块也包含了修改文件权限、判断文件权限的函数chmod、access。chmod来修改文件的权限,access用来判断文件是否具有相应的权限;Linux中,权限分为读、写和执行。因此,OS模块也提供了个常量来表示读、写、可执行权限,即R_OK、W_OK、X_OK。
下面程序演示了chmod、access函数的用法;首先通过命令行读取文件的名称,先判断文件是否存在,如果文件存在,则直接退出,然后判断文件是否具有读权限,如果没有读权限,则将文件赋予所有用户都有读、写、执行权限。如果文件存在且已经具有读权限,则读取文件内容
# -*- coding: utf-8 -*- import os import sys def main(): sys.argv.append("") filename = sys.argv[1] if not os.path.isfile(filename): raise SystemExit(filename + ' does not exists') elif not os.access(filename, os.R_OK): os.chmod(filename, 0777) else: with open(filename)as f: print (f.read()) if __name__ == '__main__': main()
程序运行结果:
[root@VM-17-4-centos python]# python chmod_access.py data.txt This enables you to create a channel specific replication filter to filter out selected data from a source. When a FOR CHANNEL clause is provided, the replication filter statement acts on that replication channel, removing any existing replication filter which has the same filter type as the specified replication filters, and replacing them with the specified filter. Filter types not explicitly listed in the statement are not modified. If issued against a replication channel which is not configured, the statement fails with an ER_SLAVE_CONFIGURATION error. If issued against Group Replication channels, the statement fails with an ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED error. [root@VM-17-4-centos python]# python chmod_access.py data1.txt data1.txt does not exists
案例:打印最常用的10条Linux命令
当我们在Shell中输入命令并执行时,有非常多的快捷键可以提高我们的工作效率,如,我们可以在Bash中使用ctrl+r搜索曾经执行过的Linux命令,之所以可以使用ctrl+r搜索曾经执行过的Linux命令,是因为Bash跟踪用户之前输入过的命令,并将其保存在~/bash_ history文件中,我们可以使用history命令或者直接读取~/.bash_history文件的内容来查看命令历史。
~/bash_history文件保存了命令的历史,因此,我们可以使用该文件获取命令的列表统计命令的执行次数。在统计时,我们只统计命令的名称即可,以不同的参数调用相同的命令也认为是同个命令
下面的程序用来统计每条命令的出现次数,然后找出出现次数最多的10条命令如下所示:
In [1]: import os In [2]: from collections import Counter In [3]: c=Counter() In [4]: with open(os.path.expanduser('~/.bash_history')) as f: ...: for line in f: ...: cmd = line.strip().split() ...: if cmd: ...: c[cmd[0]]+=1 ...: In [5]: c.most_common(10) Out[5]: [('ll', 591), ('cd', 300), ('vim', 186), ('cat', 136), ('innobackupex', 98), ('ps', 72), ('rm', 63), ('mysql', 54), ('mkdir', 48), ('systemctl', 44)] In [6]: c.most_common(20) Out[6]: [('ll', 591), ('cd', 300), ('vim', 186), ('cat', 136), ('innobackupex', 98), ('ps', 72), ('rm', 63), ('mysql', 54), ('mkdir', 48), ('systemctl', 44), ('yum', 37), ('sh', 35), ('netstat', 30), ('free', 29), ('php', 29), ('more', 26), ('top', 24), ('pwd', 24), ('cp', 24), ('python', 23)]
高级文件处理接口shutil
如果读者对比OS模块的函数和shutil模块包中的函数,会发现它们有一些重叠;例如,os.rename用来重命名一个文件,shutil.move也可以用来重命名一个文件那么,为什么会存在两个模块提供相同功能的情况呢这就涉及准库模块的定位问题,OS模块是对操作系统的接口进行封装,主要作用是跨平台shutil模块包含复制移动、重命名和删除文件及目录的函数,主要作用是管理文件和目录因此,它们并不冲突,并且是互补的关系。对于常见的文件操作,shutil更易于使用我们应该尽可能使用shutil里面的函数,shutil面没有相功能的情况下再使用OS模块下的函数
In [1]: import shutil In [2]: ls a1.txt b1.txt c2.jpg d2.jpg e2.png e3.png testdir/ test.txt tmpdir/ In [3]: shutil.copy('test.txt','test1.txt') In [4]: ls a1.txt b1.txt c2.jpg d2.jpg e2.png e3.png test1.txt testdir/ test.txt tmpdir/ In [5]: shutil.copytree('testdir','wjqdir') In [6]: ls a1.txt b1.txt c2.jpg d2.jpg e2.png e3.png test1.txt testdir/ test.txt tmpdir/ wjqdir/ In [7]: shutil.move('test1.txt','wjqtest.txt') In [8]: ls a1.txt b1.txt c2.jpg d2.jpg e2.png e3.png testdir/ test.txt tmpdir/ wjqdir/ wjqtest.txt In [9]: import os In [11]: os.rmdir('tmpdir') --------------------------------------------------------------------------- OSError Traceback (most recent call last) in () ----> 1 os.rmdir('tmpdir') OSError: [Errno 39] Directory not empty: 'tmpdir' In [12]: shutil.rmtree('tmpdir') In [13]: ls a1.txt b1.txt c2.jpg d2.jpg e2.png e3.png testdir/ test.txt wjqdir/ wjqtest.txt