Python自动化运维 - day6 - 常用模块
re模块
re模块,包含所有正则表达式的功能,可以使用正则表达式对字符串进行匹配过滤的,那么先来看一下正则表达式。
正则表达式
正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
常用的规则如下表所示:
符号 | 含义 |
\w | 字母、数字、下划线 |
\W | 非字母、数字、下划线 |
\s | 任意空白字符串,等价于[\t\n\r\f] |
\S | 任意非空字符串 |
\d | 任意数字,等价于[0-9] |
\D | 任意非数字 |
\n | 换行符(在windows下换行符为\r\n) |
\t | 制表符 |
^ | 字符串的开头 |
$ | 字符串的结尾 |
. | 任意单个字符串,但是\n等是无法匹配到的,findall指定参数re.S(可以让.匹配到换行符) |
[...] | 用来表示一组,一个范围[a-c],等于a,b,c |
* | 表示前面的字符出现0次或者N次(前边可以是字符也可以是一个正则表达式) |
+ | 表示前面的字符出现1次或者多次(前边可以是字符也可以是一个正则表达式) |
? | 匹配前面的字符或表达式,出现0次或者1次 |
{n} | 表示前面的字符出现n次 |
{n,m} | 表示前面的字符串最少出现n次,最多出现m次 |
.* | 表示匹配任意长度的字符串(贪婪匹配) |
.*? | 表示匹配任意长度的字符串(非贪婪匹配), |
a|b | 匹配a或b,如果匹配到a就不会继续匹配b,没有匹配到a才会继续匹配b |
() | 分组,这样只会返回分组里面的内容,就算后面有其他表达式也不会返回,在括号里面用?: 内部表示不单纯匹配括号里面的内容 |
compan(?:y|ies) | 等于 company | companie |
更多常用的正则表达式在线转换工具:tool.oschina.net/regex/#
功能函数
re.findall(expression,val)
从val的左边进行查找,查找所有expression匹配到的字符串,并用list进行存储
例子:匹配所有的数字 s = '1-2*(60+(-40.35/5.3+1.2)-(-4*3))' num = re.findall('\-?\d+\.?\d*',s) #会匹配所有数字,包涵正负数,小数等 扩展:re.findall(r'\-?\d+\.\d+|(\-?\d+)','1-2*(60+(-40.35/5.3+1.2)-(-4*3))') 由于使用了(),既只显示()里面匹配到的元素,既只匹配到了正负整数
re.search(expression,val)
从value的左边进行查找,查找匹配expression的对象,找到1个既返回,找到则返回SRE对象,找不到就返回None,通过对象的.group()方法读取匹配到的信息
例子:匹配数字 s = '1-2*(60+(-40.35/5.3+1.2)-(-4*3))' num = re.search('\-?\d+\.?\d*',s).group() #会匹配到第一个数字1, 扩展:re.search('exp1|exp2',val) 同时拿着exp1,exp2去val中匹配,满足任意一个,则返回 s = '1.3-2*(60+(-40.35/5.3+1.2)-(-4*3))' num = re.search('\-?\d+\.\d+|\-?\d+',s).group() #匹配正负整数或者正负小数,任意一个匹配到则返回
re.match(expression,val)
从value开头开始找,匹配则返回SRE对象,不匹配就返回None,功能类似于 ^
例子:匹配a s = 'daxin like Linux' match = re.match('a',s) #返回None,re.match('d',s)则返回d
group()
对表达式进行分组
re.search('al(e)x mak(e)','alex make love').group() 结果类似于findall里面的 ?: ,如果 group(1),则会匹配到底一个()里面的e,group(2),则会匹配到第二个()里面的e。 group(int) int 表示匹配到的第几个括号的内容,如果不指定,则显示所有匹配到字符串 例子: re.search('al(e)x mak(e)','alex make love').group() #结果:alex make re.search('al(e)x mak(e)','alex make love').group(1) #结果: e
re.split(expression,val)
把val按照expression进行分割,支持按照正则表达式进行分割,返回list
例子:针对数字进行分隔 s = r'9+63+2-(12*2)/9' list1 = re.split('[0-9]',s) #结果:['', '+', '', '+', '-(', '', '*', ')/', '']
re.sub('sub1','sub2',string)
把字符串中的sub1,替换为sub2
例子: s = r'1.3-2*(60+(-40.35/5.3+1.2)-(-4*3))' match = re.sub('-','A',s) #把-号,替换为A 扩展: re.sub('(\w+)(\s)(\w+)(\s)(\w)$',r'\5\2\3\4\1','alex make love') 字符串换位,后面的数字表示前面括号匹配到的字符串,类似于Linxu下的sed命令
time模块
时间戳: time.time()
从1970年开始(unix元年),的秒数
结构化时间: time.localtime() #当前时区 UTC时区time.gmtime()
元祖的形式显示时间(time.localtime().tm_year()获取年,)
格式化时间: time.strftime('%Y-%m-%d %H:%M:%S')
%X 效果等同于 %H:%M:%S
转换关系:
#时间戳 print(time.time()) #时间戳转换为结构化时间 print(time.localtime(time.time())) #时间戳转换为格式化时间(时间戳不能直接转换为格式化时间,需要使用结构化时间中继) print(time.strftime('%Y-%m-%d',time.localtime(time.time()))) #结构化时间 print(time.localtime()) #结构化时间转换为时间戳 print(time.mktime(time.localtime())) #结构化时间转换为格式化时间 print(time.strftime('%Y-%m-%d',time.localtime())) #格式化时间 print(time.strftime('%Y-%m-%d %X')) #格式化时间转换为结构化时间 print(time.strptime('2017-06-04','%Y-%m-%d')) #格式化时间转换为时间戳(格式化时间不能直接转换为时间戳,需要使用结构化时间中继) print(time.mktime(time.strptime(time.strftime('%Y-%m-%d'),'%Y-%m-%d')))
random模块
主要用来产生随机数
random.random() 0和1之间的小数
>>> random.random() 0.37989514876249375 >>> random.random() 0.3337038388412016 >>>
random.randint(1,3) 取出1-3之间的整数,包含1,3
>>> random.randint(1,10) 4 >>> random.randint(1,10) 9 >>> random.randint(1,10) 1 >>>
random.randrange(1,3) 取出1-3之间的整数,和普通 range 用法相同,顾前不顾后. (包含1不包含3)
>>> random.randrange(1,4) 2 >>> random.randrange(1,4) 1 >>> random.randrange(1,4) 2 >>>
random.choice(iterable) 随机在iterable中去随机抽取一个对象
>>> random.choice([1,2,3,4,5,6]) 1 >>> random.choice([1,2,3,4,5,6]) 4 >>> random.choice([1,2,3,4,5,6]) 3 >>>
random.sample(iterable,int) 每次在iterable对象中选取 int 个元素,组成列表并返回
>>> random.sample([1,2,3,4,5,6,7,8],3) [2, 8, 4] >>> random.sample([1,2,3,4,5,6,7,8],3) [4, 7, 8] >>> random.sample([1,2,3,4,5,6,7,8],3) [1, 6, 8] >>>
random.uniform(1,3) 随机选出1和3之间的小数
>>> random.uniform(1,2) 1.343193035913123 >>> random.uniform(1,2) 1.8532874990121724 >>> random.uniform(1,2) 1.960351385197145 >>>
random.shuffle(itarable) 把 iterable 对象 的顺序进行打乱(洗牌)
>>> a = [ i for i in range(100)] >>> random.shuffle(a) >>> a [46, 24, 48, 17, 50, 10, 34, 90, 29, 33, 85, 21, 71, 14, 78, 58, 55, 54, 45, 12, 60, 70, 66, 73, 95, 23, 59, 69, 68, 35, 88, 93, 53, 84, 61, 36, 82, 30, 31, 20, 56, 64, 4, 40, 42, 32, 7, 77, 27, 22, 1, 74, 28, 19, 96, 8, 94, 80, 2, 9, 16, 44, 57, 11, 41, 92, 5, 43, 83, 81, 37, 47, 15, 86, 6, 13, 89, 87, 79, 98, 38, 72, 99, 51, 63, 26, 0, 18, 67, 3, 91, 25, 97, 62, 76, 75, 65, 52, 49, 39] >>>
注意:会直接作用在iterabel对象上,不会产生副本
例子:编写随机验证码
1 import random 2 3 def check(n): 4 code = '' 5 for i in range(n): 6 num = random.randint(1,9) 7 s = chr(random.randint(65,90)) 8 add = random.choice([num,s]) 9 code += str(add) 10 return code 11 12 print(check(3))
os模块
os.getcwd():获取当前路径 os.chdir():切换当前目录,当路径中存在\的时候,由于是转意的意思,那么就需要对\进行转意,那么路径就是c:\\User,或者在目录前面加r,表示后面的字符串不进行解释 os.curdir():获取当前目录名 os.pardir():获取上级目录名 os.mkdir('dir'):创建目录,注意只能创建一级目录 os.makedirs('dir_path'):创建多级目录 os.rmdir('dir'):删除一个目录 os.removedir('dir_path'):删除多级目录(目录为空的话) os.listdir('dir'):显示目录下的所有文件,默认为当前目录,返回的结果为list os.remove('file'):删除一个文件 os.rename('old_name','new_name'):修改文件名称 os.stat('file/dir'):获取文件/目录的stat信息 os.sep:返回当前操作系统的路径分隔符 Windows下:\\ , Linux下:/ os.linesep:返回当前操作系统的换行符 Windows下:\r\n ,Linux下:\n os.pathsep:返回当前操作系统环境变量分隔符 Windows下:; , Linux下: : os.name:返回当前系统的类型 nt 表示Windows, posix表示Linux os.system('Commmand'):执行命令 os.environ:获取系统环境变量,使用字典存储 os.path.abspath('dir/file'):获取dir/file的绝对路径 os.path.split('path'):把路径分割为目录和文件名组成的元组格式,不管path是否存在 os.dirname('path'):获取文件的父目录名称,不管path是否存在 os.basename('path'):获取文件的名称,不管path是否存在 os.path.exists('path'):判断path是否存在,return bool os.path.isabs('path'):判断path是否是从根开始,return bool Linux下:从/开始 Windows下从C,D,E盘开始 os.path.isfile('path'):判断path是否是一个文件 os.path.isdir('path'):判断path是否是一个目录 os.path.join('path1','path2','path3'):把path1和path2及path3进行组合,但如果path2中包含了根路径,那么就会舍弃path1,从path2开始组合 os.path.getatime('path'):获取文件的atime时间,返回时间戳 os.path.getmtime('path'):获取文件的mtime时间,返回时间戳 os.path.getsize(filename): 获取文件的大小,单位是字节
os.walk
日常的工作中,可能常常需要使用查找某个目录下的符合某些规则的文件,并且可能是递归查询,对于这类需求可以使用os.walk模块。
walk函数便利某个目录及其子目录,对于每一个目录,os.walk返回一个三元组(dirpath,dirnames,filenames)。
-
- dirname:表示目录名
- dirnames:表示目录下的子目录名称
- filenames:表示目录下的文件名
>>> name = os.walk('/Users/DahlHin/Python') # 返回的是一个生成器 >>> for roots,dirs,filenames in name: for file in filenames: filename = os.path.join(roots,file) file_list.append(filename) # file_list 则存储了Python目录下的所有文件
列出目录下所有以.txt结尾的文件
>>> >>> import fnmatch >>> import os >>> file_list = [] >>> name = os.walk('/Users/DahlHin/Python') >>> for roots,dirs,files in name: for file in files: filename = os.path.join(roots,file) if fnmatch.fnmatch(filename,"*.txt"): file_list.append(filename) >>> file_list
sys模块
sys.argv 命令行参数List,第一个元素是程序本身路径(空表示当前目录) sys.exit(n) 退出程序,如果n为数字的话,那么就是 echo $?的值,如果是 str,那么会直接打印在屏幕上 sys.version 获取python解释器的版本信息 sys.maxint 获取当前操作系统最大的int值(2.x的时候,32位主机和64为主机int值范围不同) --> python 2 sys.path Python的初始环境变量 sys.platform 返回操作系统的平台名称 sys.stdout 标准输出(其实就是屏幕,本质上标注你输出也是一个文件,也有write方法) sys.stdout.write('str') 把 str 写到标准输出中去 注意:'\r'跳到行首
PS:在sys.path中添加当前目录,可以让Python解释器,在当前目录寻找模块,或者包,不过还有另一种方法是设置环境变量PYTHONPATH
,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
shutil模块
shutil.copyfileobj(fsrc,fdes,length) 将文件内容拷贝到另一个文件中,可以只拷贝部分内容,需要我们自行打开文件对象进行copy
>>> import os,shutil >>> os.system('ls') 1.txt >>> shutil.copyfileobj(open('1.txt'),open('2.txt','w')) >>> os.system('ls') 1.txt 2.txt >>>
shutil.copyfile(fsrc,fdes) 复制文件,我们只需要传入文件名称即可进行复制,不用自行预先打开,等于创建一个新的文件,把老文件写入到新文件中然后关闭,新创建的文件权限和属主等信息遵循操作系统规定
>>> shutil.copyfile('1.txt','3.txt') >>> os.system('ls') 1.txt 2.txt 3.txt
shutil.copymode(src,des) 复制文件权限,既把src文件的权限复制给 des文件,只改变权限,不改变其他比如属组,内容等(des文件必须存在)
>>> os.system('ls -l') total 12 -rwxrwxrwx 1 root root 6 Mar 9 18:35 1.txt -rw-r--r-- 1 root root 6 Mar 9 18:36 2.txt -rw-r--r-- 1 root root 6 Mar 9 18:38 3.txt >>> shutil.copymode('1.txt','2.txt') >>> os.system('ls -l') total 12 -rwxrwxrwx 1 root root 6 Mar 9 18:35 1.txt -rwxrwxrwx 1 root root 6 Mar 9 18:36 2.txt -rw-r--r-- 1 root root 6 Mar 9 18:38 3.txt >>>
shutil.copystat(src,des) 复制文件的权限,还包括,atime,mtime,flags等信息,不改变文件内容(des需存在)
>>> os.system('stat 1.txt') File: `1.txt' Size: 6 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 926326 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-09 18:36:59.223738919 +0800 Modify: 2017-03-09 18:35:23.148738381 +0800 Change: 2017-03-09 18:39:59.061738605 +0800 >>> os.system('stat 3.txt') File: `3.txt' Size: 6 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 940237 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-09 18:39:42.214738376 +0800 Modify: 2017-03-09 18:38:13.862738316 +0800 Change: 2017-03-09 18:38:13.862738316 +0800 >>> shutil.copystat('1.txt','3.txt') >>> os.system('stat 3.txt') File: `3.txt' Size: 6 Blocks: 8 IO Block: 4096 regular file Device: fd00h/64768d Inode: 940237 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-03-09 18:36:59.223738000 +0800 Modify: 2017-03-09 18:35:23.148738000 +0800 Change: 2017-03-09 18:44:33.286738354 +0800 >>>
shutil.copy(src,des) 复制文件的同时复制权限信息(等于shutil.copyfile + shutil.copystat)
shutil.copytree(des,src,ignore = shutil.ignore_patterns('*py')) 递归复制文件,类似于copy -r
>>> os.system('ls -l') total 4 drwxr-xr-x 2 root root 4096 Mar 9 18:46 test >>> shutil.copytree('test','test1') >>> os.system('ls -l') total 8 drwxr-xr-x 2 root root 4096 Mar 9 18:46 test drwxr-xr-x 2 root root 4096 Mar 9 18:46 test1 >>> os.system('ls -l test1') total 12 -rwxrwxrwx 1 root root 6 Mar 9 18:35 1.txt -rwxrwxrwx 1 root root 6 Mar 9 18:36 2.txt -rwxrwxrwx 1 root root 6 Mar 9 18:35 3.txt >>>
shutil.rmtree(des) 递归的删除文件,类似于 rm -rf
>>> os.system('ls -l') total 8 drwxr-xr-x 2 root root 4096 Mar 9 18:46 test drwxr-xr-x 2 root root 4096 Mar 9 18:46 test1 >>> shutil.rmtree('test1') >>> os.system('ls -l') total 4 drwxr-xr-x 2 root root 4096 Mar 9 18:46 test >>>
shutil.move(src,des) 移动文件/目录,类似于mv 命令
shutil.make_archive('data_bak','gztar',roots_dir = '/data' ) 压缩,data_bak 可以写为绝对路径
import tarfile t = tarfile.open('data_bak.tar.gz') #打开我呢间 t.extractall('/tmp') #解压缩到某个路径 t.close() #tar打包 t = tarfile.open('data_bak.tar','w') t.add(r'/tmp/1.txt') --> #会把程序的路径也进行打包 t.close() #tar打包 t =tarfile.open('data_bak.tar.gz') t.add('/tmp/1.txt',arcname='1.txt_bak') # 打包的时候把 /tmp/1.txt 打包成 1.txt_bak
json&pickle模块
为什么要序列化
1、持久保存状态
2、跨平台数据交互
如何序列化:
1、json(跨平台) 支持字典(dict)、列表(list)、字符串(str)、整型浮点型(int/float)、bool(True,False),null(None)
2、pickle(纯Python)
eval不能识别非Python语法的数据类型,所以很多时候要用json
json
序列化:
import json string = json.dumps(obj) #直接把obj转换成str with open('a.json','w') as f: f.write(string)
反序列化:
import json with open('a.json','r') as f: res = f.read() json.loads(res) #把str转换成Python识别的数据格式
直接序列化到文件中去:
import json json.dump(obj,文件对象(w方式))
直接从文件中反序列化:
import json json.load(文件对象(r模式)
PS:Json默认情况下,dumps()
方法不知道如何将类
实例变为一个JSON的{}
对象。可选参数default
就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为类专门写一个转换函数,再把函数传进去即可:
import json class Student(object): def __init__(self,name,age,job): self.name = name self.age = age self.job = job def converclass(std): return { 'name':std.name, 'age':std.age, 'job':std.job } a = Student('daxin',20,'Pythoner') a_json = json.dumps(a,default=converclass) print(a_json)
但是如果再来一个Teacher类的话,那么上面的转换方法就不适用了,这里我们可以偷个懒,使用类的__dict__属性
import json class Student(object): def __init__(self,name,age,job): self.name = name self.age = age self.job = job a = Student('daxin',20,'Pythoner') a_json = json.dumps(a,default=lambda obj:obj.__dict__) print(a_json)
同样反序列化的时候,使用object_hook可以定制反序列化的规则
import json class Student(object): def __init__(self,name,age,job): self.name = name self.age = age self.job = job a = Student('daxin',20,'Pythoner') a_json = json.dumps(a,default=lambda obj:obj.__dict__) def restoclass(s): return Student(s['name'],s['age'],s['job']) b = json.loads(a_json,object_hook=restoclass)
pickle
序列化:需要用b模式打开文件
import pickle dic = { 'name':'daxin', 'age':18, 'job':'Linux' } pic_dumps = pickle.dumps(dic) #序列化存储 with open('a.pickle','wb') as fd: fd.write(pic_dumps)
反序列化:
import pickle with open('a.pickle','rb') as fd: dic = pickle.loads(fd.read())
直接序列化到文件中去:
import pickle dic = { 'name':'daxin', 'age':18, 'job':'Linux' } pickle.dump(dic,open('b.pickle','wb'))
直接从文件中反序列化:
import pickle with open('b.pickle','rb') as fd: print(pickle.loads(fd.read()))
小结
1、json是通用的格式,如果涉及多个系统之间的交互,选用json
2、pickle是python特有的,可以序列化一些python独特的数据类型,比如函数
3、pickle序列化函数的时候,只会序列化函数的内存地址,在脚本执行完毕,那么函数的内存地址就会释放,在其他文件反序列化的时候,那么因为原脚本已经执行完毕,原函数已经释放,所以就会报找不到该函数
shevle模块
shelve是一个简单的k,v将内存数据通过文件持久化的模块,是对pickle的更高级的封装,可以持久化任何pickle可支持的python数据格式,可以对数据进行多次的dump和load,而不用担心数据混乱。
注意:它的格式为k,v存储。默认会生成三个文件(.bak/.dat/.dir)
例子: import shelve l = [1,2,3,4,5] d = {'name':'daxin','age':20} s = {1,2,3,4,5} #dump f = shelve.open('shevle') f['l'] = l f['d'] = d f['s'] = s f.close() #load t = shelve.open('shevle') print(t['l']) print(t['d']) print(t['s']) t.close()
hashlib模块
用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
使用方法1:
1 hashlib.md5('str').hexdigest() #用MD5对str进行加密,使用hexdigest(),16进制的方式打印
使用方法2:
1 md5 = hashlib.md5() 2 md5.update('hello') #如果第一次执行update,那么就是对hello这个字符串进行MD5加密(注意,这里是累加,如果多次update,那么求得是累加的md5值) 3 md5.hexdigest() #把md5对象保存的str,以16进制进行显示
例子:把文件读入,然后用md5进行校验
import hashlib import sys def md5sum(f): m = hashlib.md5() with open(f) as fd: while True: data = fd.read(4096) if data: m.update(data) else: break return m.hexdigest() if __name__ == '__main__': try: print md5sum(sys.argv[1]),sys.argv[1] except IndexError as e: sys.stderr.write('%s want a file\n' % __file__)
以上加密算法,可以通过撞库(枚举),去破解,所以我们可以在字符前面加上指定的字符串进行二次加密
>>> import hashlib >>> m = hashlib.md5('12asvac23as') >>> m.update('hello') >>> m.hexdigest() 'cedc722f4b9836fb510c1cc5a4af890c' >>>
subprocess模块
运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。
subprocess.call('cmd') 父进程等待子进程完成,返回退出信息(return code,相当于Linux exit code),功能类似于os.system 无法捕获结果。
>>> import subprocess >>> subprocess.call('w') 19:27:07 up 4 days, 11:55, 5 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT root tty1 - Sun07 28:08m 0.03s 0.03s -bash root pts/2 10.0.0.1 17:13 1:37m 0.13s 0.13s -bash root pts/3 10.0.0.1 17:18 2:07m 0.01s 0.01s -bash root pts/4 10.0.0.1 18:01 0.00s 0.10s 0.07s python root pts/5 10.0.0.1 18:39 40:55 0.08s 0.08s -bash >>>
注意:
subprocess.call('ls -l')
注意当执行的cmd中有空格的时候,python解释器会认为后面的是文件,就会报错,那么就需要添加参数shell = True,标识使用shell的方式执行
或者使用列表 subprocess.call(['ls','-l'])
subprocess.call('ps axu | grep python',shell=True) 这样就可以
subprocess.check_call('cmd') 功能和call相同,无法捕捉结果。与call不同的是,check_call默认会检查命令的返回值,如果不是0,则会返回subprocess.CalledProcessError异常,
>>> subprocess.check_call(['rm' ,'-rf' ,'/etc/hosts']) rm: cannot remove `/etc/hosts': Permission denied Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.6/subprocess.py", line 505, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['rm', '-rf', '/etc/hosts']' returned non-zero exit status 1 >>>
try抓取subprocess.CalledProcessError异常,然后处理
[redis@linux-node1 ~]$ cat sub.py #!/usr/bin/env python import subprocess try: subprocess.check_call(['rm','-rf','/etc/hosts']) except subprocess.CalledProcessError as e: print('hello world') [redis@linux-node1 ~]$ [redis@linux-node1 ~]$ python3 sub.py rm: cannot remove `/etc/hosts': Permission denied hello world
subprocess.Popen() 调用外部命令的时候,也会像C那样fork一个子进程进行执行
通用语法1:subprocess.Popen('cmd',shell=True,stdout=subprocess.PIPE)
通用语法2:subprocess.Popen(['cmd'],stdout=subprocess.PIPE) -->一般用这种
上面两行代码功能相同,不写stdout的话,默认会把输出打印到当前的屏幕上
PIPE 表示管道符,会把命令的输出方式暂时缓存,然后通过对应的方式进行读取
p.stdout.read() 从管道符中读取命令执行结果
stdout 表示标准输出
stdin 表示标准输入
stdin=subprocess.PIPE,表示输入从PIPE读取
stderr 表示错误输出
Popen对象的方法:
p.pid 查看子进程的PID
p.poll() 查看执行状态,完毕返回0
p.returncode 获取进程的返回值
p.kill() kill掉相关进程
p.terminate() 暂停进程
p.wait() 等待进程执行完毕
p.communicate() 可以和子进程进行交互,可以给子进程的stdin传递参数(子进程的stdin为PIPE),会返回一个元组,(stdout,stderr),需要子进程也输出到PIPE,这样才能接收到 ,所以它会等待子进程执行完毕,相当于p.stdin.write()、p.stdin.close(),p.stdout.read()三个方法
例子:
p = Popen(['ls'],stdout=PIPE,stderr=PIPE) ; stdout,stderr = p.communicate() 获取p的stdout和stderr
注意:
Popen会fork一个子进程去执行命令,父脚本会继续向下执行,如果要等待Popen执行完毕,那么就需要使用p.wait()来等待子进程执行完毕,再继续执行
PIPE 管道会把命令的结果进行储存
例子:
p1 = Popen(['ls'],stdout = PIPE) p2 = Popen(['grep','py'],stdin=p1.stdout,stdout=PIPE) p2.stdout.read()
log模块
主要用于输出日志信息的模块,其根据日志的级别分为六部分:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL,只有大于当前日志等级的操作才会被记录。
例子:直接输出日志到屏幕上
1 import logging 2 3 logging.warning('user [root] attempted wrong password more than 3 times') 4 logging.critical('Mysql Service is gone down')
如果想把日志输出到文件中去
1 import logging 2 logging.basicConfig(filename='access.log',level=logging.INFO) #这里可以使用日志级别对应的数字进行指定 3 logging.info('hello info') 4 logging.warning('hello warning') 5 logging.error('hello error')
指定日志格式
1 import logging 2 3 logging.basicConfig(filename='access.log', level=logging.INFO, 4 format = '%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s', 5 datefmt = '%Y-%m-%d %X') 6 logging.info('hello info') 7 logging.warning('hello warning')
logging.basicConfig函数各参数:
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a'
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略
format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
%(name)s Logger的名字 %(levelno)s 数字形式的日志级别() %(levelname)s 文本形式的日志级别 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 %(filename)s 调用日志输出函数的模块的文件名 %(module)s 调用日志输出函数的模块名 %(funcName)s 调用日志输出函数的函数名 %(lineno)d 调用日志输出函数的语句所在的代码行 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 %(thread)d 线程ID。可能没有 %(threadName)s 线程名。可能没有 %(process)d 进程ID。可能没有 %(message)s 用户输出的消息
日志等级(数字表达形式):
CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
confingparser模块
用于生成和修改常见配置文档,比如:MySQL
在2.x里,模块名为ConfigParser,在3.x里为configparser
在configparser的参数通过字典进行定义
例子:利用configparser编写一个配置文件
1 import configparser 2 3 config = configparser.ConfigParser() # 实例化一个配置对象 4 #定义方法1:直接利用key:value定义 5 config['Default'] = {'name':'daxin','age':20,'job':'Linux'} 6 7 #定义方法2: 8 config['Global'] = {} 9 config['Global']['name'] = 'daxin' 10 config['Global']['age'] = '20' 11 config['Global']['job'] = 'Linux' 12 13 #定义方法3: 14 config['localhost'] = {} 15 localconfig = config['localhost'] 16 localconfig['name'] = 'daxin' 17 localconfig['age'] = '20' 18 localconfig['job'] = 'Linux' 19 20 #写入配置文件 21 with open('example.ini','w') as fd: 22 config.write(fd) #这里的确是通过实例化的对象的write,写入一个打开的文件中去
读取配置文件内容:
1 # Author:Lee Sir 2 3 import configparser 4 conf = configparser.ConfigParser() #创建一个configparser对象 5 conf.read('example.ini') #读取配置文件 6 for node in conf.sections(): #sections表示列出配置文件中配置段的title 7 print(node) 8 for item in conf[node]: 9 print(item,conf[node][item])
XML模块
xml可扩展标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。
功能是实现不同语言或程序之前进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,json还没有诞生的黑暗年代,大家只能选择用xml进行数据交换,所以很多老系统的接口还是xml
xml的格式,主要通过<>节点来区别数据结构的
示例数据:
1 <?xml version="1.0"?> 2 <data> 3 <country name="Liechtenstein"> 4 <rank updated="yes">2</rank> --> rank为开头 /rank为结尾 5 <year>2008</year> 6 <gdppc>141100</gdppc> 7 <neighbor name="Austria" direction="E"/> 8 <neighbor name="Switzerland" direction="W"/> 9 </country> 10 <country name="Singapore"> 11 <rank updated="yes">5</rank> 12 <year>2011</year> 13 <gdppc>59900</gdppc> 14 <neighbor name="Malaysia" direction="N"/> 15 </country> 16 <country name="Panama"> 17 <rank updated="yes">69</rank> 18 <year>2011</year> 19 <gdppc>13600</gdppc> 20 <neighbor name="Costa Rica" direction="W"/> neighbor/自结束标签,可以在/之前添加参数等 21 <neighbor name="Colombia" direction="E"/> 22 </country> 23 </data>
利用python处理xml数据
python有三种方法来解析xml,SAX、DOM、以及ElementTree
因为elementTree更轻量级,所以这里用ElementTree进行学习
例子:
# Author:Lee Sir import xml.etree.ElementTree as ET #引入ElementTree模块对xml进行处理 tree = ET.parse("xmltest.xml") #ElementTree.parse(source,parser=None) 将xml文件进行加载,并返回ElementTree对象,parser表示使用什么解析器,默认使用标准的xml解析器 root = tree.getroot() #得到根节点,返回根节点的element对象(既最外层的tag名称),这里也可以使用find,查找匹配到的第一个tag,tree.find('data'),并返回以该tag为起始的根结点树状结构 print(root.tag) #打印最外层的tag的名称 # 遍历xml文档 for child in root: #遍历根节点 print(child.tag, child.attrib) #打印根节点下的tag的名称和属性 for i in child: #如果有嵌套tag,那么打印tag的名称是对应的值 print(i.tag, i.text) # 只遍历year 节点 for node in root.iter('year'): #root.iter对所有tag节点进行过滤year print(node.tag, node.text) #打印对应的tag名称和值
增删改查:
http://www.tuicool.com/articles/fmMz2m