Python subprocess模块高级API详解:run、call与check系列方法
本文深入解析Python subprocess模块的高级API方法。重点介绍subprocess.run()及其capture_output、timeout、check等关键参数,对比分析subprocess.call()、check_call()和check_output()的使用场景与注意事项。同时涵盖getstatusoutput()等兼容旧版的方法,帮助开发者安全高效地调用外部进程。
subprocess.run()方法详解
subprocess.run()
该方法用于执行由args参数指定的命令,并等待其完成,最终返回一个CompletedProcess实例以包含执行结果。
其参数列表为(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs)。除了input、capture_output、timeout和check这四个特定参数外,其余参数均与Popen构造器的参数保持一致。
当capture_output设置为True时,系统会将stdout和stderr重定向至管道。此时若再显式传递stderr或stdout参数,程序将抛出异常,因为这两个输出流已被自动接管。
input参数作为标准输入传递给Popen的communicate()方法,其值必须为字符串(需指定encoding或errors参数,或设置text=True)或字节类型。若input不为None,则严禁与stdin参数同时使用,否则引发异常;此时Popen实例的stdin参数将被自动设置为subprocess.PIPE。
timeout参数直接传递给Popen的communicate()方法,用于限制命令执行的超时时间。
若check设置为True,当进程执行返回非0状态码时,将抛出CalledProcessError异常,以便开发者捕获处理错误。
# 源码
def run(*popenargs, input=None, capture_output=False, timeout=None, check=False, **kwargs):
if input is not None:
if 'stdin' in kwargs:
raise ValueError('stdin and input arguments may not both be used.')
kwargs['stdin'] = PIPE
if capture_output:
if ('stdout' in kwargs) or ('stderr' in kwargs):
raise ValueError('stdout and stderr arguments may not be used '
'with capture_output.')
kwargs['stdout'] = PIPE
kwargs['stderr'] = PIPE
with Popen(*popenargs, **kwargs) as process:
try:
stdout, stderr = process.communicate(input, timeout=timeout)
except TimeoutExpired:
process.kill()
stdout, stderr = process.communicate()
raise TimeoutExpired(process.args, timeout, output=stdout,
stderr=stderr)
except: # Including KeyboardInterrupt, communicate handled that.
process.kill()
# We don't call process.wait() as .__exit__ does that for us.
raise
retcode = process.poll()
if check and retcode:
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
return CompletedProcess(process.args, retcode, stdout, stderr)
Python 3.5前的高级API方法
在Python 3.5版本之前,subprocess模块的高级API主要由call()、check_call()和check_output()这三个方法构成。
subprocess.call()的使用
subprocess.call()
该函数运行并等待args参数指定的指令完成,返回执行状态码,即Popen实例的returncode属性值。
其参数为(*popenargs, timeout=None, **kwargs),与Popen构造器参数基本相同,除timeout外的所有参数都会传递给Popen接口。
调用call()函数时,应避免使用stdout=PIPE或stderr=PIPE。如果子进程产生的输出量足以填满操作系统的管道缓冲区,子进程将因无法从管道读取数据而阻塞。
# 源码
def call(*popenargs, timeout=None, **kwargs):
with Popen(*popenargs, **kwargs) as p:
try:
return p.wait(timeout=timeout)
except:
p.kill()
p.wait()
raise
subprocess.check_call()与错误处理
subprocess.check_call()
该函数运行并等待args参数指定的指令完成。若执行成功,返回0状态码;若失败,则抛出CalledProcessError异常。通过该异常的cmd和returncode属性,可以查看导致异常的指令及其状态码。
其参数为(*popenargs, **kwargs),所有参数均传递给call()函数处理。
其注意事项与call()函数相同,需特别注意管道缓冲区阻塞问题。
# 源码
def check_call(*popenargs, **kwargs):
retcode = call(*popenargs, **kwargs)
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd)
return 0
subprocess.check_output()与输出捕获
subprocess.check_output()
该函数运行并等待args参数指定的指令完成,返回标准输出内容(即CompletedProcess实例的stdout属性)。默认返回类型为byte字节,具体编码可能取决于执行的指令。若设置universal_newlines=True,则返回string类型的值。若执行状态码非0,将抛出CalledProcessError异常。
其参数为(*popenargs, timeout=None, **kwargs),所有参数均传递给run()函数,但不支持显式传递input=None以继承父进程的标准输入文件句柄。
若需在返回值中捕获标准错误,可设置stderr=subprocess.STDOUT;或者将标准错误重定向至管道(stderr=subprocess.PIPE),随后通过CalledProcessError异常的stderr属性进行访问。
# 源码
def check_output(*popenargs, timeout=None, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
if 'input' in kwargs and kwargs['input'] is None:
# Explicitly passing input=None was previously equivalent to passing an
# empty string. That is maintained here for backwards compatibility.
kwargs['input'] = '' if kwargs.get('universal_newlines', False) else b''
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
**kwargs).stdout
兼容旧版命令的方法
subprocess模块还保留了Python 2.x版本中commands模块的相关函数,以兼容旧代码。
getstatusoutput()与getoutput()
subprocess.getstatusoutput(cmd)
该函数实际调用check_output()方法,在shell中执行字符串类型的cmd指令,返回一个(exitcode, output)形式的元组。其中output部分包含stderr和stdout,是使用locale encoding解码后的字符串,并已去除结尾的换行符。
# 源码
try:
data = check_output(cmd, shell=True, universal_newlines=True, stderr=STDOUT)
exitcode = 0
except CalledProcessError as ex:
data = ex.output
exitcode = ex.returncode
if data[-1:] == '\n':
data = data[:-1]
return exitcode, data
subprocess.getoutput(cmd)
该函数与getstatusoutput()类似,但结果仅返回output部分,不包含退出状态码。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









