Python subprocess模块用来管理子进程,以取代一些旧模块的方法(如os.system、os.spawn*、os.popen*、popen2.*、commands.*)。不但可以调用外部的命令作为子进程,而且可以连接到子进程的input/output/error管道,获取相关的返回信息。

1、subprocess常用函数

运行Python时,我们都是创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程执行另外一个程序。而在Python中,可以通过标准库中的subprocess模块来fork一个子进程,并运行一个外部的程序。

subprocess模块中定义有多个以不同方式创建子进程的函数,另外还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

 

subprocess.call():父进程等待子进程完成,返回退出信息(returncode,相当于Linux exit code)

subprocess.check_call():父进程等待子进程完成,返回0。

检查退出信息,如果returncode不为0,则抛出subprocess.CalledProcessError,该异常包含有returncode属性,可用try...except...来捕获。

subprocess.check_output():父进程等待子进程完成,返回子进程向标准输出的结果。

检查退出信息,如果returncode不为0,则抛出subprocess.CalledProcessError,该异常包含有returncode属性和output属性,其中output属性为标准输出的结果,可用try...except...来捕获。

示例1:

#####Windows######
>>> import subprocess
>>> retcode = subprocess.call(['ipconfig', '/all'])
>>> retcode
0

#####Linux#####
>>> import subprocess
>>> retcode = subprocess.call(["ls", "-l"])
>>> retcode
0

将程序名(ipconfig或ls)和所带的参数(/all或-l)一起放在一个表中传递给subprocess.call()。shell默认为False,在Linux下,shell=False时,Popen调用os.execvp()执行args指定的程序;shell=True时,如果args是字符串,Popen直接调用系统的Shell来执行args指定的程序,如果args是一个序列,则args的第一项是定义程序命令的字符串,其他项是调用系统Shell时的附加参数。

而在Windows下,不论shell值如何,Popen调用CreateProcess()执行args指定的外部程序。如果args是一个序列,则先用list2cmdline()转化为字符串。

 

subprocess.run():Python3.5版本后新增。

>>> subprocess.run("ipconfig")
CompletedProcess(args='ipconfig', returncode=0)
>>> subprocess.run(["ipconfig", "/all"])
CompletedProcess(args=['ipconfig', '/all'], returncode=0)

  

subprocess.Popen():call()、check_call()、check_output()默认内部调用的都是subprocess.Popen(),与它们不同,使用subprocess.Popen()创建Popen对象后,主程序不会自动等待子进程完成,必须调用对象的wait()方法,父进程才会等待(也就是阻塞block)。

>>> child = subprocess.Popen(['ping', '192.168.1.1'])
>>> print('parent process')
parent process
>>> child = subprocess.Popen(['ping', '192.168.1.1]).wait()
>>> print('parent process')
parent process

  

Popen实例属性及方法:

Popen.poll():检查子进程状态

Popen.kill():终止子进程

Popen.send_signal():向子进程发送信号

Popen.terminate():终止子进程

Popen.pid:子进程Pid号

 

示例2:

# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# 执行标准输入,write后面是输入的命令
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
# 输入之后关闭
obj.stdin.close()

# 读取标准输出的内容,赋值给cmd_out对象
cmd_out = obj.stdout.read()
# 关闭标准输出
obj.stdout.close()

# 读取错误输出的内容,赋值给cmd_error对象
cmd_error = obj.stderr.read()

# 关闭错误输出
obj.stderr.close()

# 输出内容
print("标准输出为:\n" + cmd_out)
print("错误输出为:\n" + cmd_error)

##########执行结果##########
标准输出为:
1
2

错误输出为:

 

示例3:

# 导入subprocess模块
import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")

# communicate把错误输出或者标准输出的内容赋值给out_error_list对象,如果有错误就赋值错误输出,否则就复制标准输出
out_error_list = obj.communicate()

# 输出out_error_list对象的内容
print(out_error_list)

##########执行结果##########
('1\n2\n', '')

  

示例4:

# 导入subprocess模块
import subprocess

obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)


# 直接执行print("hello")命令,然后把错误或者正确的结果赋值给out_error_list对象
out_error_list = obj.communicate('print("hello")')

# 输出out_error_list对象的内容
print(out_error_list)

##########执行结果##########
('hello\n', '')