python之路-Day6

time & datetime模块

#_*_coding:utf-8_*_
__author__ = 'Alex Li' import time # print(time.clock()) #返回处理器时间,3.3开始已废弃 , 改成了time.process_time()测量处理器运算时间,不包括sleep时间,不稳定,mac上测不出来
# print(time.altzone) #返回与utc时间的时间差,以秒计算\
# print(time.asctime()) #返回时间格式"Fri Aug 19 11:14:16 2016",
# print(time.localtime()) #返回本地时间 的struct time对象格式
# print(time.gmtime(time.time()-800000)) #返回utc时间的struc时间对象格式 # print(time.asctime(time.localtime())) #返回时间格式"Fri Aug 19 11:14:16 2016",
#print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上 # 日期字符串 转成 时间戳
# string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #将 日期字符串 转成 struct时间对象格式
# print(string_2_struct)
# #
# struct_2_stamp = time.mktime(string_2_struct) #将struct时间对象转成时间戳
# print(struct_2_stamp) #将时间戳转为字符串格式
# print(time.gmtime(time.time()-86640)) #将utc时间戳转换成struct_time格式
# print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将utc struct_time格式转成指定的字符串格式 #时间加减
import datetime # print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
#print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19
# print(datetime.datetime.now() )
# print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分 #
# c_time = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #时间替换

python之路-Day6

import time
a= time.strptime('2016/11/12','%Y/%m/%d')
print(a)
b= time.mktime(a)
print(b)
c= time.gmtime(b)
print(c)
d= time.strftime('%Y-%m-%d',c)
print(d) #转换回来后,时间会有相差

random模块

import random
print(random.random()) #用于生成一个0到1的随机符点数: 0 <= n < 1.0
print(random.randint(1,2))
print(random.randrange(1,4)) #随机生成的数字中不包含最后一个数字。 随机数字的生成
import random
code = ''
for i in range(6):
a = random.randint(1,6)
if a == i:
temp = chr(random.randint(65,90)) #chr对应assci表
else:
temp = random.randint(0,9)
code +=str(temp)
print(code)

shutile模块

高级的 文件、文件夹、压缩包 处理模块

shutil.copyfileobj(fsrc, fdst[, length]),其中length指定缓冲区大小

将文件内容拷贝到另一个文件中,可以部分内容

import shutil
f1 = open('1.py',encoding='utf-8')
f2 = open('haha.txt','w',encoding='utf-8')
shutil.copyfileobj(f1,f2,length=5)

shutil.copyfile(src, dst)
拷贝文件

复制文件src到文件或目录dst。如果dst是目录,使用src相同的文件名创建(或覆盖),权限位也会复制。src和dst的是字符串形式的路径名。

shutil.copymode(src,dst)

仅拷贝权限。内容、组、用户均不变

shutil.copystat(src, dst)拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copy(src,dst) 拷贝文件和权限
shutil.copy('1.py',r'f:\456')

shutil.copy2(src,dst) 拷贝文件和权限,拷贝文件和状态信息

shutil.copy2('haha.txt',r'f:\456')

shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件

shutil.copytree('D:\\py_s15\\练习',r'f:\457')  目的地址不能存在,自动会创建

shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件

shutil.move(src, dst)
递归的去移动文件

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

    • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
      如:www                        =>保存至当前路径
      如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
    • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
    • root_dir: 要压缩的文件夹路径(默认当前目录)
    • owner: 用户,默认当前用户
    • group: 组,默认当前组
    • logger: 用于记录日志,通常是logging.Logger对象

import shutil
ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
 
 
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置 /Users/wupeiqi/目录
import shutil
ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
 
import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close() # 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall()
z.close() zipfile 压缩解压

import tarfile

# 压缩
tar = tarfile.open('your.tar','w')
tar.add('/Users/wupeiqi/PycharmProjects/bbs2.zip', arcname='bbs2.zip')
tar.add('/Users/wupeiqi/PycharmProjects/cmdb.zip', arcname='cmdb.zip')
tar.close() # 解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
tar.close() tarfile 压缩解压
configparser模块
用于生成和修改常见配置文档,当前模块的名称在 python 2.x中,模块名字为:ConfigParser
常见文档格式
1
2
3
4
5
6
7
8
9
10
11
12
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
 
[bitbucket.org]
User = hg
 
[topsecret.server.com]
Port = 50022
ForwardX11 = no
那么,如何生成此类型文档
import configparser
config = configparser.ConfigParser()
config['DEFAULT'] = {'ServerAliverInterval':'',
'Compression':'yes',
'CompressionLevel':''}
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = ''
topsecret['ForwardX11'] = 'no'
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini','w') as configfile:
config.write(configfile)

并将其中元素读取出来

print(config.sections())
print(config['bitbucket.org']['User'])

configparser增删改查语法

print(config.sections())  #没有读文件,所以sections就没数据
config.read('example.ini') #读取一个文件
print(config.sections()) #DEFAULT默认不显示,但是DEFAULT可以单独打印
print(config.defaults())
print(config['bitbucket.org']['User']) #读取某个内容
print(config.options(config.sections()[1])) #只打印DEFAULT和最后一个
print(config.items(config.sections()[1])) #打印key和value对应的关系
config.remove_option(config.sections()[1],'forwardx11 = no') #删除
config.set(config.sections()[1],'host port','') #修改
config.add_section('bbbbb.edu') #增加section
config.write(open('example_new.ini','w'))

logging模块

很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug()info()warning()error() and critical() 5个级别,下面我们看一下怎么用。

看一下这几个日志级别分别代表什么意思

Level When it’s used
DEBUG Detailed information, typically of interest only when diagnosing problems.
INFO Confirmation that things are working as expected.
WARNING An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.
ERROR Due to a more serious problem, the software has not been able to perform some function.
CRITICAL A serious error, indicating that the program itself may be unable to continue running.

最简单用法

1
2
3
4
5
6
7
8
import logging
 
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
 
#输出
WARNING:root:user [alex] attempted wrong password more than 3 times
CRITICAL:root:server is down

 如果想把日志写到文件里,也很简单

import logging
logging.basicConfig(filename='example.log',level=logging.INFO) #将info以及更严重级别的日志输入的文件中
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
logging.error('wolrd ge')

其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。

感觉上面的日志格式忘记加上时间啦,日志不知道时间怎么行呢,下面就来加上!

import logging
logging.basicConfig(filename='example.log',format='%(asctime)s %(message)s',datefmt='%m/%d/%Y %I:%M:%S %p',level=logging.INFO)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
logging.error('wolrd ge')

日志格式(添加到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

用户输出的消息

 


如果想同时把log打印在屏幕和文件日志里,就需要了解一点复杂的知识 了


Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:


logger提供了应用程序可以直接使用的接口;


handler将(logger创建的)日志记录发送到合适的目的输出;


filter提供了细度设备来决定输出哪条日志记录;


formatter决定日志记录的最终输出格式。


logger
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)


Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别



handler


handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象


每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr


2) logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。


3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。


4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨

import logging
logger = logging.getLogger('a.txt') #自己想取得名字
logger.setLevel(logging.DEBUG) #设置最低等级
#如果想输出到文件,并且输出到屏幕,就要设置handler,并且把handler加入到logger中。
ch = logging.StreamHandler() #屏幕输出
ch.setLevel(logging.WARNING) #屏幕输出级别
fh = logging.FileHandler('access.log') #文件输出
fh.setLevel(logging.ERROR)
#定义日志格式
fh_formate = logging.Formatter('%(asctime)s %(message)s %(levelname)s %(pathname)s %(lineno)d %(funcName)s',
datefmt='%m/%d/%Y %I:%M:%S %p')
ch_formate = logging.Formatter('%(asctime)s %(message)s %(levelname)s %(lineno)d',
datefmt='%m/%d/%Y %I:%M:%S %p')
#设置屏幕和文件输入格式
ch.setFormatter(ch_formate)
fh.setFormatter(fh_formate)
#告诉logger,分别往两个地方输出
logger.addHandler(fh)
logger.addHandler(ch) logger.warning('dddd') #如果不设置输出位置,默认输出到屏幕
logger.error('cccc')

python之路-Day6

可以根据时间和大小对日志文件进行切割(需要单独import一个handler)

1.通过大小

import logging
from logging import handlers
logger = logging.getLogger('TEST')
log_file = 'timelog.log' #将产生的日志放入该文件。
fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3) #(文件、字节、备份文件数)
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning('test1')
logger.warning('test12')
logger.warning('test13')
logger.warning('test14')
logger.warning('test15')
logger.warning('test16')

2.通过时间

import logging
import time
from logging import handlers
logger = logging.getLogger('TEST')
log_file = 'timelog.log' #将产生的日志放入该文件。
fh = handlers.TimedRotatingFileHandler(filename=log_file,when='S',interval=5,backupCount=3)
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning('test1')
time.sleep(2)
logger.warning('test12')
time.sleep(2)
logger.warning('test13')
logger.warning('test14')
time.sleep(2)
logger.warning('test15')
logger.warning('test16')

hashlib模块

import hashlib
m = hashlib.md5()
m.update(b'alex') #在3.0中,必须要变成byte才能mds
print(m.hexdigest())
m.update(b'li')
print(m.hexdigest()) #此行打印的结果是alex与li一同计算的出的md5 m2 = hashlib.md5() #这种的出来的md5值与上面的最后一次打印出的md5值相同,也就是说一行一行读会,md5值会重新计算,类似于一行一行读文件,对文件进行md5验证
m2.update(b'alexli')
print(m2.hexdigest())
#md5各种算法,只是算法不同
# hashlib.sha1
#hashlib.sha256
# hashlib.sha224
# hashlib.sha384
# hashlib.sha512
import hmac import hmac #通过key与value,用于网络消息传输加密
h = hmac.new(b'wueiqi',b'hello')
print(h.hexdigest())

xml

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。

xml的格式如下,就是通过<>节点来区别数据结构的:

import xml.etree.ElementTree as ET
tree = ET.parse('txt.xml')
root = tree.getroot()
print(root.tag )
#遍历xml文档
for chiled in root:
print(chiled.tag,chiled.attrib)
for i in chiled:
print(i.tag,i.text) #过滤
for node in root.iter('year'):
print(node.tag,node.text)
#修改
for node in root.iter('year'):
new_year = int(node.text) +1
node.text = new_year
node.text = str(new_year)
node.set('updated','yes')
tree.write('txt1.xml')
#删除
for country in root.findall('country'):
if int(country.find('rank').text)> 50:
root.remove(country)
tree.write('txt3.xml') #创建
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
age = ET.SubElement(name, "age", attrib={"checked": "no"})
sex = ET.SubElement(name, "sex")
sex.text = ''
name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
age = ET.SubElement(name2, "age")
age.text = ''
et = ET.ElementTree(new_xml) # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True)
ET.dump(new_xml) # 打印生成的格式

shelve 模块

shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式

import shelve
 
d = shelve.open('shelve_test') #打开一个文件
def stu_data(name,age):    
  print('stu',name,age)
name = ['alex','lwq','hsc']
d['hsc'] = named
['lwq'] = name
d.close()
可再从另一个文件中打开
import shelve
f = shelve.open('shevel_test')
print(f['hsc'])
print(f['lwq'])
print(f['wt'])
这样的操作可以重复进行,此模块的功能就是可以多次序列化和反序列化。

re模块 

正则表达式符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*'     匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0
'{m}'   匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
 
 
'\A'    只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'    匹配字符结尾,同$
'\d'    匹配数字0-9     如果想去两个数,用groups(),只能写成(\d{2}),不能写成(\d){2},这样groups就只会取最后一个数字。
'\D'    匹配非数字
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
's'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
 
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果
import re a = re.search('\d.*\d\Z','44oimfd33')  #返回第一个符合规则的 
print(a.group())
b = re.findall('\d+','44adfdc4545rgkfdgk6666') #返回所有符合规则的,以列表的形式返回
print(b)
c = re.split('\d+','44adfdc4545rgkfdgk6666') #反向选取,如果前面不是数字就返回空
print(c)

最常用的匹配语法

1
2
3
4
5
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub      匹配字符并替换  (1.规则2.要替换成什么3.字符串4.次数 5.flag是忽略大小写)

反斜杠的困扰
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

仅需轻轻知道的几个匹配模式

1
2
3
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^''$'的行为(参见上图)
S(DOTALL): 点任意匹配模式,改变'.'的行为

  

Subprocess模块 

常用subprocess方法示例

os.system 输出命令结果到屏幕,返回命令执行状态 
os.popen('dir').read 会将命令执行后的结果保存,但是不会输出,如果想读取:os.popen(‘dir’).read()
即想保存结果,又想保存执行状态
python2.7
commands
commands.getstatusoutput subprocess.run()是在python3.5以后出现的。

#执行命令,返回命令执行状态 , 0 or 非0 >>> retcode = subprocess.call(["ls", "-l"])

#执行命令,如果命令结果为0,就正常返回,否则抛异常 >>> subprocess.check_call(["ls", "-l"]) 0

#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果 >>> subprocess.getstatusoutput('ls /bin/ls') (0, '/bin/ls')

#接收字符串格式命令,并返回结果 >>> subprocess.getoutput('ls /bin/ls') '/bin/ls'

#执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res >>> res=subprocess.check_output(['ls','-l']) >>> res b'total 0\ndrwxr-xr-x  12 alex  staff  408 Nov  2 11:05 OldBoyCRM\n'

#上面那些方法,底层都是封装的subprocess.Popen

>>> b = subprocess.Popen('sleep 5;echo hello',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> b.stdout.read()
'hello\n'

poll()     Check if child process has terminated.  Returns returncode

print(b.poll())

none就是没执行完,0就是执行完毕

wait()     Wait for child process to terminate.  Returns returncode attribute.

一直等到程序结束后返回结果,poll是没执行完返回none,执行完返回0

terminate() 杀掉所启动进程 communicate()  等待任务结束

b.terminate()

stdin 标准输入
stdout 标准输出
stderr 标准错误

pid     The process ID of the child process.

#例子 >>> p = subprocess.Popen("df -h|grep disk",stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True) >>> p.stdout.read() b'/dev/disk1     465Gi   64Gi  400Gi    14% 16901472 104938142   14%   /\n'

1
2
3
4
5
6
7
8
9
10
11
>>> subprocess.run(["ls", "-l"])  # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
 
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
 
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

调用subprocess.run(...)是推荐的常用方法,在大多数情况下能满足需求,但如果你可能需要进行一些复杂的与系统的交互的话,你还可以用subprocess.Popen(),语法如下:

1
2
p = subprocess.Popen("find / -size +1000000 -exec ls -shl {} \;",shell=True,stdout=subprocess.PIPE)
print(p.stdout.read())

可用参数:

    • args:shell命令,可以是字符串或者序列类型(如:list,元组)
    • bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
    • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
    • preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
    • close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。 所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
    • shell:同上
    • cwd:用于设置子进程的当前目录
    • >>> b = subprocess.Popen(['pwd'],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd='/tmp')
      >>> b.stdout.read()
      '/tmp\n'
    • env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
    • universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
    • startupinfo与createionflags只在windows下有效 将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等

终端输入的命令分为两种:

  • 输入即可得到输出,如:ifconfig
  • 输入进行某环境,依赖再输入,如:python

需要交互的命令示例

1
2
3
4
5
6
7
8
9
10
import subprocess
 
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n ')
obj.stdin.write('print 2 \n ')
obj.stdin.write('print 3 \n ')
obj.stdin.write('print 4 \n ')
 
out_error_list = obj.communicate(timeout=10)
print out_error_list

subprocess实现sudo 自动输入密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import subprocess
 
def mypass():
    mypass = '123' #or get the password from anywhere
    return mypass
 
echo = subprocess.Popen(['echo',mypass()],
                        stdout=subprocess.PIPE,
                        )
 
sudo = subprocess.Popen(['sudo','-S','iptables','-L'],
                        stdin=echo.stdout,
                        stdout=subprocess.PIPE,
                        )
 
end_of_pipe = sudo.stdout
 
print "Password ok \n Iptables Chains %s" % end_of_pipe.read()

  

上一篇:centos7 安装 iRedmail 后 给nginx添加虚拟主机


下一篇:[2017-7-27]Android Learning Day5