其实有一个模块也支持执行系统命令,那个模块就是sys.system,但他执行系统命令会直接通过主进程去执行命令,那假如,该命令的执行需要耗费一个小时,那么主进程会卡一个小时,而不会去干别的事,这样就会导致程序的运行效率低下。
如果由subprocess去执行系统命令的时候并不会让主进程去执行,而是主进程会开辟出一个子进程去执行,并不会影响到主进程的运行,主进程该干嘛就干嘛,那么又有个问题,大家都知道进程之间的内存空间是独立的,也就是说进程之间是不能相互访问的,那么在subprocess中,有个管道的概念,既然固定死了进程之间不能相互访问,那么可以将执行命令的结果输出到管道里,该管道其实就是一块共享的内存空间,可以让主进程去获取到该共享内存空间存放的数据。
实例 : 用一个子进程来执行命令
import subprocess
obj = subprocess.Popen('systeminfo', # 执行系统命令(必须是字符串的格式)
shell=True, # 指定命令解释器来执行这条命令
stdout=subprocess.PIPE, # 将执行的正确结果丢到管道(共享空间,用于进程之间的共享)
stderr=subprocess.PIPE, # 将执行的错误结果丢到另一个新的管道
)
# 取出正确的结果
res1 = obj.stdout.read() # 主进程去管道里获取正确的结果
print(res1.decode('gbk')) # 获取的结果是 bytes 类型,需要指定decode指定编码
# 取出错误的管道中的结果
res2 = obj.stderr.read()
print(res2.decode('utf-8', 'ignore'))
Subprocess 模块其他参数说明
subprocess.Popen(args,
bufsize=0,
executable=None,
stdin=None,
stdout=None,
stderr=None,
preexec_fn=None,
close_fds=False,
shell=False,
cwd=None,
env=None,
universal_newlines=False,
startupinfo=None,
creationflags=0))
args 参数,可以是一个字符串,也可以是一个包含程序参数的列表,要执行的程序一般就是这个列表的第一项,或者是字符串本身。
如果 args是一个列表,则第一项被视为命令,其余的视为给shell 本身的参数。
subprocess.Popen([“cat”,“test.txt”])
subprocess.Popen(“cat test.txt”)
这两个之中,后者将不会工作。因为如果是一个字符串的话,必须是程序的路径才可以。(考虑unix的api函数exec,接受的是字符串
列表)
后者要执行的话需要指定参数 shell = True 即:
subprocess.Popen(“cat test.txt”, shell=True)
shlex.split()可以被用于序列化复杂的命令参数,比如:
>>> shlex.split('ls ps top grep pkill')
['ls', 'ps', 'top', 'grep', 'pkill']
stdin stdout和stderr:
stdin stdout和stderr,分别表示子程序的标准输入、标准输出和标准错误。可选的值有PIPE或者一个有效的文件描述符(其实是个正
整数)或者一个文件对象,还有None。如果是PIPE,则表示需要创建一个新的管道,如果是None
,不会做任何重定向工作,子进程的文件描述符会继承父进程的。另外,stderr的值还可以是STDOUT
,表示子进程的标准错误也输出到标准输出。
其他相关的命令
1、subprocess.call
subprocess.call (*popenargs , **kwargs )
执行命令,并等待命令结束,再返回子进程的返回值。参数同Popen。
2、subprocess.check_call
subprocess.check_call (*popenargs , **kwargs )
执行上面的call命令,并检查返回值,如果子进程返回非0,则会抛出CalledProcessError异常,这个异常会有个returncode
属性,记录子进程的返回值。
3、Popen 对象说明
参考博客链接:subprocess.Popen()详解