python 基础模块之 subprocess模块。
subprocess模块运行系统命令,管理子进程。是对这些命令的替换 os.system 和 os.spawn* ,所以尽量用subprocess。运维的小伙伴们,以后或多或少会用到subprocess这个模块。
run() 运行命令
python3.5之后有了subprocess.run(),这个是官方推荐的运行系统命令的方法。用nslookup举例:
import subprocess
subprocess.run(["nslookup","www.baidu.com 202.96.209.5"]) # 参数写在一起貌似没问题
subprocess.run(["nslookup","-qt=cname","www.baidu.com","202.96.209.5"]) # 不过最好还是分开写
subprocess.run("nslookup -qt=cname www.baidu.com 202.96.209.5",shell=True) # 也可以全部混在一起写,但是shell参数得设成True
上面的shell参数,主要是用在涉及到命令行中有多个命令的情况。因为默认只会解析列表的第一个元素作为命令,后面都是命令的参数。具体情况,比如Linux中的管道命令:ls -l | grep test
上面只有屏幕输出,也可以取得返回值,包括命令的参数和执行的结果:
import subprocess
res = subprocess.run(["nslookup","www.baidu.com","202.96.209.5"])
print(res)
print(res.returncode) # 取得命令的结果
相关命令和参数,可以help(subprocess.Popen) 查看,因为底层其实是通过subprocess.Popen来实现的
run很方便,但是如果想要获取屏幕上的输出保存,那就需要用底层的Popen来实现了。用stdout来指定程序的标准输出。
import subprocess
res = subprocess.Popen(
["nslookup","www.baidu.com","202.96.209.5"],
stdout=subprocess.PIPE) # 将标准输出指向PIPE
res_read = res.stdout.read() # 和文件一样,read完就没了,所以先read到变量里
print(res_read) # 这里读到的内容是二进制
print((res_read).decode("gbk")) # 将二进制转码,这里是操作系统的编码格式,我用的是windows,所以是gbk
print(res.poll()) # 最后2个属性返回的都是命令执行的结果,即returncode。正常执行应该都是返回0
print(res.wait())
参数说明:
run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;
poll() 和 wait() 的区别
- poll():检查是否结束,设置并返回returncode属性。
- wait():等待结束,设置并返回returncode属性。
所以命令运行时间长的时候,wait()会一直等下去,poll()会直接返回,如果还没有结束,返回None
import subprocess,time
res = subprocess.Popen(
["nslookup","www.baidu.com","209.96.209.5"],
stdout=subprocess.PIPE) # 这里用一个不存在的地址,这样命令要等待很久
# print("wait:",res.wait()) # 去掉注释,看看wait的效果
while res.poll()==None:
print("poll:",res.poll())
time.sleep(1)
print("end poll",res.poll())
使用poll,在运行命令等待结果的同时,并不会中断python的运行,可以随时用poll检查命令是否执行完成。
terminate() 终止进程,kill
import subprocess,time
res = subprocess.Popen(
["nslookup","www.baidu.com","1.1.1.1"],
stdout=subprocess.PIPE # 这里用一个不存在的地址,这样命令要等待很久
)
n = 3
while n > 0:
print("poll:",res.poll())
time.sleep(1)
n -= 1
else:
if res.poll() == None:
print("end process")
res.terminate() # 如果还没执行完,就终止进程
print(res.stdout.read()) # 这里是空的,因为并没有结果
如果一段时间内没有执行完成,就终止这个进程。把最后的参数改成一个有响应的IP,不会超时就可以顺利执行完。
communictae(input=None)
和子进程交互:发送数据到stdin,并从stdout和stderr读数据,直到收到EOF,等待子进程结束。可选的input如有有的话,要为bytes类型。
此函数返回一个元组:标准输出和错误 (stdoutdata , stderrdata ) 。
主要用于需要交互的命令(nslookup telnet这种):
import subprocess
p = subprocess.Popen('nslookup',shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) # 输入、输出、错误都得进管道
p.stdin.write(b'server 114.114.114.114 \n') # 只接收bytes,记得要打上回车符
p.stdin.write(b'www.baidu.com \n')
p.stdin.write(b'exit \n')
res = p.communicate() # 上面的write只是写入到内存,这句才是把之前写入的所有的内容传给进程来执行
# res = p.communicate(b"exit \n") # input参数没啥用,这个效果测试下来等于上面2句
print(res[0].decode("gbk")) # 第一个元素是标准输出
print(res[1].decode("gbk")) # 第二个是标准错误。"非权威应答:"作为错误信息返回了
参数说明:
● 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:默认False,如果为True,指定的命令会在shell里解释执行。
● cwd:用于设置子进程的当前目录
● env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
● universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
● startupinfo与createionflags只在windows下有效将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
使用subprocess写个ping程序
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Ljohn
# Description:subprocess模块,Ping程序(windwos)
# Import the module
import subprocess
# Ask the user for input
host = input("Enter a host to ping: ")
# Set up the echo command and direct the output to a pipe
p1 = subprocess.Popen(['ping', host], stdout=subprocess.PIPE)
# Run the command
output = p1.communicate(b"exit \n") #把input输入的内容传给进程来执行。
print (output[0].decode("gbk")) #第一个元素是标准输出,第二个元素是标准错误输出
View Code