subprocess
模块允许启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
subprocess
模块首先推荐使用的是它的 run
方法,更高级的用法可以直接使用 Popen 接口。
run
方法
语法格式如下:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)
args
:表示要执行的命令。必须是一个字符串,字符串参数列表。stdin
、stdout
和stderr
:子进程的标准输入、输出和错误。 其值可以是subprocess.PIPE
、subprocess.DEVNULL
、一个已经存在的文件描述符、已经打开的文件对象或者None
。subprocess.PIPE
表示为子进程创建新的管道。subprocess.DEVNULL
表示使用os.devnull
。 默认使用的是None
,表示什么都不做。另外,stderr
可以合并到stdout
里一起输出。timeout
:设置命令超时时间。如果命令执行时间超时,子进程将被杀死,并弹出TimeoutExpired
异常。check
:如果该参数设置为True
,并且进程退出状态码不是 0,则弹出CalledProcessError
异常。encoding
: 如果指定了该参数,则stdin
、stdout
和stderr
可以接收字符串数据, 并以该编码方式编码。否则只接收bytes
类型的数据。shell
:如果该参数为True
,将通过操作系统的shell
执行指定的命令。run
方法调用方式返回CompletedProcess
实例,和直接Popen
差不多,实现是一样的, 实际也是调用Popen
,与Popen
构造函数大致相同,例如:
实例: 执行ls -l /dev/null
命令.
import subprocess
subprocess.run(["ls", "-l", "/dev/null"])
crw-rw-rw- 1 nobody nogroup 1, 3 Apr 14 07:36 /dev/null
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0)
returncode
: 执行完子进程状态,通常返回状态为 0
则表明它已经运行完毕,
若值为负值 "-N"
, 表明子进程被终。
简单实例:
import subprocess
def runcmd(command):
ret = subprocess.run(command,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding="utf-8",timeout=1)
if ret.returncode == 0:
print("success:",ret)
else:
print("error:",ret)
序列参数:
runcmd(["dir","/b"])
success: CompletedProcess(args=['dir', '/b'], returncode=0, stdout='chapter_操作系统_ch9138.ipynb\nsec01_Python的subprocess模块用法_jtc9b8.ipynb\nsec02_从Python启动其他程序_jt67c3.ipynb\nsec03_Python3多线程一_jt64ab.ipynb\nsec04_Python3多线程二_jtf146.ipynb\n', stderr='')
字符串参数:
runcmd("exit 1")
error: CompletedProcess(args='exit 1', returncode=1, stdout='', stderr='')
Popen()
方法
Popen 是 subprocess
的核心,子进程的创建和管理都靠它处理。
构造函数:
class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False, pass_fds=(),
*, encoding=None, errors=None)
常用参数:
args
:shell
命令,可以是字符串或者序列类型(如:list,元组)。bufsize
:缓冲区大小。当创建标准流的管道对象时使用,默认-1。0
:不使用缓冲区。1
:表示行缓冲,仅当universal_newlines=True
时可用,也就是文本模式。正数:表示缓冲区大小;负数:表示使用系统默认的缓冲区大小。stdin
,stdout
,stderr
:分别表示程序的标准输入、输出、错误句柄。preexec_fn
:只在 Unix 平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用。shell
:如果该参数为True
,将通过操作系统的shell
执行指定的命令。cwd
:用于设置子进程的当前目录。env
:用于指定子进程的环境变量。如果env = None
,子进程的环境变量将从父进程中继承。
创建一个子进程,执行一个简单的命令:
import subprocess
p = subprocess.Popen('ls -l', shell=True)
total 60 -rwxr-xr-x 1 jovyan users 2125 Apr 8 02:14 chapter_操作系统_ch9138.ipynb -rwxr-xr-x 1 jovyan users 11981 Apr 10 01:03 sec01_Python的subprocess模块用法_jtc9b8.ipynb -rwxr-xr-x 1 jovyan users 13741 Apr 10 01:03 sec02_从Python启动其他程序_jt67c3.ipynb -rwxr-xr-x 1 jovyan users 9827 Apr 10 01:03 sec03_Python3多线程一_jt64ab.ipynb -rwxr-xr-x 1 jovyan users 15678 Apr 10 01:03 sec04_Python3多线程二_jtf146.ipynb
p.returncode
p.wait()
p.returncode
0
p = subprocess.Popen('ls -l', shell=True, cwd = '/tmp' )
total 0
这里也可以使用 p = subprocess.Popen(['ls', '-cl'])
来创建子进程。
import time
import subprocess
def cmd(command):
subp = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding="utf-8")
subp.wait(2)
if subp.poll() == 0:
print(subp.communicate()[1])
else:
print("失败")
cmd("java -version")
cmd("exit 1")
失败 失败