17.5. subprocess —— 子进程管理

源代码: Lib/subprocess.py

subprocess模块允许你生成新进程,连接到其输入/输出/错误管道,并获取其返回码。此模块旨在替换多个旧的模块和函数:

os.system
os.spawn*

有关如何使用subprocess模块来替换这些模块和函数,请参见以下部分。

另可参阅

PEP 324 —— 提议subprocess模块的PEP

17.5.1. 使用subprocess模块

调用subprocess的推荐方法是对于它可以处理的所有使用场景都使用run()函数。对于更高级的使用场景,可以直接使用底层的Popen接口。

run()函数是在Python 3.5中添加的;如果你需要保留与旧版本的兼容性,请参阅旧版高级API部分。

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False)

运行args描述的命令。等待命令完成,然后返回一个CompletedProcess实例。

上面显示的参数只是最常见的参数,在下面的常用参数中描述(因此在这个简写形式中使用keyword-only写法)。完整的函数形式很大程度上与Popen构造函数相同 —— 除timeoutinputcheck之外,该函数的所有参数都传递给Popen接口。

默认情况下,它不捕获标准输出或标准错误。如果要这样做,请为stdout和/或stderr参数传递PIPE

timeout参数被传递给Popen.communicate()如果timeout超时,子进程将被终止并等待。子进程终止后,将重新引发TimeoutExpired异常。

input参数传递给Popen.communicate(),因此传递到子进程的标准输入。如果使用,它必须是字节序列,或者如果universal_newlines=True,则为字符串。用到时,会自动以stdin=PIPE创建内部的Popen对象,也可能用不到stdin参数。

如果check为True,并且进程以非零退出码退出,则会引发CalledProcessError异常。该异常的属性中保存有参数、 退出码和标准输出及标准错误(如果它们被捕捉到)。

例子:

>>> subprocess.run(["ls", "-l"])  # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

版本3.5中的新功能。

class subprocess.CompletedProcess

run()返回的值,表示已完成的进程。

args

用于启动进程的参数。这可能是一个列表或字符串。

returncode

子进程的退出状态。通常,退出状态为0表示它已成功运行。

负值-N表示子进程被信号N终止(仅POSIX)。

stdout

从子进程中捕获的标准输出。一个字节序列,如果run()universal_newlines=True调用则为一个字符串。如果没有捕获标准输出,则为None。

如果使用stderr=subprocess.STDOUT运行进程,stdout和stderr将在此属性中合并,stderr将为None。

stderr

从子进程中捕获的标准错误。一个字节序列,如果run()universal_newlines=True调用则为一个字符串。如果没有捕获标准错误,则为None。

check_returncode()

如果returncode不为零,则引发CalledProcessError

版本3.5中的新功能。

subprocess.DEVNULL

可用作Popenstdinstdoutstderr参数的特殊值,指示将使用os.devnull这个特殊文件。

版本3.3中的新功能。

subprocess.PIPE

可用作Popenstdinstdoutstderr参数的特殊值,表示应打开相应标准流的管道。主要用于Popen.communicate()

subprocess.STDOUT

可用作Popenstderr参数的特殊值,表示标准错误应与标准输出放在同一句柄中。

exception subprocess.SubprocessError

此模块中所有其他异常的基类。

版本3.3中的新功能。

exception subprocess.TimeoutExpired

SubprocessError的子类,当等待子进程的timeout超时时引发。

cmd

用于产生子进程的命令。

timeout

超时(以秒为单位)。

output

子进程的输出(如果它由run()check_output()捕获)。否则,为None

stdout

用于输出的别名,为了与stderr对称。

stderr

子进程的标准错误输出(如果它由run()捕获)。否则,为None

版本3.3中的新功能。

在版本3.5中的更改:添加stdoutstderr属性

exception subprocess.CalledProcessError

SubprocessError子类,当check_call()check_output()运行的进程返回非零退出状态时引发。

returncode

子进程的退出状态。如果进程由于信号而退出,则它将是负的信号数。

cmd

用于产生子进程的命令。

output

子进程的输出(如果它由run()check_output()捕获)。否则,为None

stdout

用于输出的别名,为了与stderr对称。

stderr

子进程的标准错误输出(如果它由run()捕获)。否则,为None

在版本3.5中的更改:添加stdoutstderr属性

17.5.1.1. 常用参数

为了支持各种各样的场景,Popen构造函数(和其便利函数)接受大量的可选参数。对于大部分典型的使用场景,这些参数中的许多个可以安全地保持为默认值。最常用到的参数有:

args是所有调用所必需的,应该为一个字符串或一个程序参数序列。通常倾向提供参数序列,因为它允许这个模块来处理任何所需的转义和引用参数(例如,允许文件名中的空格)。如果传递单个字符串,shell必须为True(见下文),否则字符串必须简单地命名要执行的程序而不指定任何参数。

stdinstdoutstderr分别指定执行程序的标准输入,标准输出和标准错误文件句柄。有效值有PIPEDEVNULL,一个存在的文件描述器(正整数),一个存在的文件对象和NonePIPE表示应该为子进程创建新的管道。DEVNULL表示将使用特殊文件os.devnull使用默认设置None,则不会发生重定向;子进程的文件句柄将从父进程继承。此外,stderr可以是STDOUT,表示来自子进程的标准错误数据应该捕获到与stdout相同的文件句柄中。

如果universal_newlinesFalse,则文件对象stdinstdoutstderr将以二进制流打开,并且不对行结束进行转换。

如果universal_newlinesTrue,则这些文件对象将使用locale.getpreferredencoding(False)返回的编码以通用换行符格式的文本流打开。对于stdin,输入中的行结束字符'\n'将转换为默认行分隔符os.linesep对于stdoutstderr,输出中的所有行结尾将转换为'\n'有关详细信息,请参阅io.TextIOWrapper类的文档中其构造函数的newline参数为None的时候。

注意

文件对象Popen.stdinPopen.stdoutPopen.stderr的新行属性不会由Popen.communicate()方法更新。

如果shellTrue,则将通过shell执行指定的命令。如果你使用Python主要是由于它能提供大多数系统shell不能提供的增强的控制流,并且仍然希望方便地访问其他shell功能,如shell管道、文件名通配符、环境变量扩展和扩展到用户的主目录,这会很有用。但是请注意,Python本身提供许多类shell特性的实现(特别是globfnmatchos.walk()os.path.expandvars()os.path.expanduser()shutil)。

版本3.3中的变化:universal_newlinesTrue时,类使用locale.getpreferredencoding(False)而不是locale.getpreferredencoding()的编码。有关此更改的详细信息,请参阅io.TextIOWrapper类。

注意

在使用shell=True之前,请先阅读安全注意事项部分。

这些选项以及所有其他选项在Popen构造函数文档中有更详细的描述。

17.5.1.2. Popen构造函数

此模块中,底层的进程创建和管理由Popen类处理。它提供很多灵活性,以便开发人员能够处理便利函数未涵盖的较不常见的情况。

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=())

在新的进程中执行子程序。在POSIX上,该类使用类似os.execvp()的行为来执行子程序。在Windows上,该类使用Windows的CreateProcess()函数。Popen的参数如下。

args 应该是一个程序参数的序列或者一个单一的字符串。默认情况下,如果args 是一个序列,那么执行的程序是args 的第一个元素。如果args 是一个字符串,那么其解释将与平台无关并在下文有描述。其它与默认行为的区别,参见shellexecutable 参数。除非另外说明,建议传递一个序列给args

在POSIX上,如果args是字符串,则该字符串将被解释为要执行的程序的名称或路径。然而,这只能在不传递参数给程序时可行。

注意

shlex.split()在确定args的正确分词时很有用,尤其是在复杂情况下:

>>> import shlex, subprocess
>>> command_line = input()
/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
>>> args = shlex.split(command_line)
>>> print(args)
['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
>>> p = subprocess.Popen(args) # Success!

特别要注意,shell中由空格分隔的选项(例如-input)和参数(例如eggs.txt)在不同的列表元素中,而shell中需要引号和反斜线转义的参数(例如包含空格的文件名和上面展示的echo 命令)是单一的列表元素。

在Windows上,如果args是一个序列,则它将按照将参数序列转换为Windows上的字符串中所述的方式转换为字符串。这是因为底层的CreateProcess()对字符串进行操作。

shell 参数(默认为False)指定是否使用shell来执行程序。如果shellTrue,则建议传递一个字符串而不是序列给args

在POSIX上,如果shell=True,则shell默认为/bin/sh如果args 是一个字符串,该字符串指定通过shell执行的命令。这意味着该字符串必须和在shell提示符中输入的格式完全一致。包括,例如,引号和反斜线转义文件名中的空格。如果args是一个序列,第一个元素指定命令行字符串,其它额外的任何元素将作为shell本身的额外的参数。也就是说,Popen相当于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在Windows上,如果shell=TrueCOMSPEC环境变量指定默认的shell。你需要在Windows上指定shell=True的唯一时候是当你希望执行的命令是shell中内置的(例如dircopy)。你不需要shell=True来运行批处理文件或基于控制台的可执行文件。

注意

在使用shell=True之前,请先阅读安全注意事项部分。

在创建stdin/stdout/stderr管道文件对象时,bufsize将作为相应的参数提供给open()函数。

  • 0表示无缓冲(读和写是一个系统调用,可以返回short)
  • 1表示行缓冲(仅在universal_newlines=True时可用,即以文本模式)
  • 任何其他正值表示使用大约该大小的缓冲器
  • 负bufsize(默认值)表示将使用io.DEFAULT_BUFFER_SIZE的系统默认值。

在版本3.3.1中更改: bufsize现在默认为-1,默认情况下启用缓冲以匹配大多数代码所期望的行为。在Python 3.2.4和3.3.1之前的版本中,它不正确地默认为0,这是未缓冲的,并允许短读。这是无意的,并且不匹配大多数代码预期的Python 2的行为。

executable 参数指定一个要执行的替换程序。它很少需要用到。shell=False时,executable替换由args指定的要执行的程序。但是,原始的args 仍然会传给该程序。大部分程序将args 当做命令的名字,它可以不同于真实执行的程序。在POSIX上,args的名称成为ps等工具中显示的可执行文件名称。如果shell=True,则在POSIX上,executable参数指定默认/bin/sh的替换shell。

stdinstdoutstderr 分别指定程序的标准输入、标准输出和标准错误文件的句柄。有效值为PIPEDEVNULL、已经存在的文件描述器(正整数)、已经存在的文件对象NonePIPE表示应该创建子进程的新管道。DEVNULL表示将使用特殊文件os.devnull使用默认设置None,不会发生重定向;子进程的文件句柄将从父进程继承。此外,stderr可以是STDOUT,这表示来自应用程序的stderr数据应该捕获到与stdout相同的文件句柄中。

preexec_fn 如果设定为一个可调用对象,该对象将在子进程中在子进程执行之前调用。(仅POSIX)

警告

在应用程序中存在线程时,preexec_fn参数不安全。在调用exec之前,子进程可能死锁。如果你必须使用它,请保持它特别简单!最小化调用的库的数量。

注意

如果需要修改子进程环境,请使用env参数,而不要在preexec_fn中修改。start_new_session参数可以取代先前常用的preexec_fn来在子进程中调用os.setsid()。

如果close_fds为真,除了012之外的所有文件描述器都将在子进程执行之前关闭。(仅POSIX)。默认值因平台而异:在POSIX上始终为真。在Windows上,当stdin/stdout/stderrNone时为真,否则为假。在Windows上,如果close_fds为真,则子进程不会继承任何句柄。注意,在Windows上,你不可以设置close_fds 为真并同时通过设置stdinstdout 或者stderr重定向标准句柄 。

在版本3.2中已更改: close_fds的默认值已从False更改为上述内容。

pass_fds是一个可选的由文件描述符组成的序列,表示在父进程和子进程之间保持打开。传递任何pass_fds都将强制使得close_fds设置为True(仅POSIX)

版本3.2中的新功能:添加了pass_fds参数。

如果cwd不为None,则在执行子进程之前,该函数将工作目录更改为cwd特别地,如果可执行路径是相对路径,则该函数寻找相对于cwd可执行文件(或args中的第一个项目)。

如果restore_signals为真(默认值),在子进程执行之前,将Python设置为SIG_IGN的所有信号在子进程中恢复为SIG_DFL。目前,这包括SIGPIPE、SIGXFZ和SIGXFSZ信号。(仅POSIX)

在版本3.2中已更改:添加restore_signals

如果start_new_session为真,则在子进程中在执行子进程之前进行setsid()系统调用。(仅POSIX)

在版本3.2中已更改:添加start_new_session

如果env不为None,则它必须是定义新进程的环境变量的映射;它们被用来代替继承当前进程环境这一默认行为。

注意

如果指定,env 必须提供要执行程序的任何变量。On Windows, in order to run a side-by-side assembly the specified env must include a valid SystemRoot.

如果universal_newlinesTrue,则文件对象stdinstdoutstderr作为通用换行模式的文本流,如上述常用参数中所述,否则它们将作为二进制流打开。

如果给定,startupinfo将是一个STARTUPINFO对象,它传递给底层的CreateProcess函数。creationflags(如果给定)可以是CREATE_NEW_CONSOLECREATE_NEW_PROCESS_GROUP(只在Windows上)

Popen对象通过with语句支持上下文管理器:在退出时,标准文件描述器被关闭,进程被等待。

with Popen(["ifconfig"], stdout=PIPE) as proc:
    log.write(proc.stdout.read())

在版本3.2中更改:添加对上下文管理器的支持。

17.5.1.3. 异常

在子进程中引发的异常,在新程序开始执行之前将在父进程中被重新引发。此外,异常对象还将有一个名为child_traceback的额外属性,该属性是一个字符串,包含来自子进程视角的回溯信息。

最常见的异常是OSError例如,当试图执行一个不存在的文件时会发生该异常。应用程序应准备OSError异常的代码。

如果使用不合法的参数调用Popen,则会引发ValueError

如果被调用的进程返回非零返回码,则check_call()check_output()将引发CalledProcessError

如果在进程退出之前超时,所有接受timeout参数的函数和方法都将引发TimeoutExpired ,例如call()Popen.communicate()

此模块中定义的异常都继承自SubprocessError

版本3.3中的新功能:添加了SubprocessError基类。

17.5.2. 安全性考虑

与其他popen函数不同,这个实现不会隐式调用系统shell。这意味着所有的字符包括shell元字符,都可以安全地传递给子进程。如果通过shell=True显式调用shell,则应用程序有责任确保所有空格和元字符都被适当引用以避免shell注入漏洞。

当使用shell=True时,可以使用shlex.quote()函数正确地转义用于构建shell命令的字符串中的空格和shell元字符。

17.5.3. Popen对象

Popen类的实例具有以下方法:

Popen.poll()

检查子进程是否已经终止。设置并返回returncode属性。

Popen.wait(timeout=None)

等待子进程终止。设置并返回returncode属性。

如果进程在timeout秒后未终止,则引发TimeoutExpired异常。捕获此异常并重试等待是安全的。

注意

当使用stdout=PIPEstderr=PIPE时,如果子进程向管道生成足够的输出以致阻塞并等待操作系统管道缓冲区接受更多数据,将会死锁。在使用管道时,请使用Popen.communicate()来避免这个问题。

注意

该函数使用频繁的循环(非阻塞调用和短暂休眠)实现。异步等待请使用asyncio模块:请参阅asyncio.create_subprocess_exec

在版本3.3中更改:添加timeout

自版本3.4后已弃用:不要使用endtime参数。它在3.3中是无意暴露的,但是没有文档,因为它是私有的供内部使用。请改用timeout

Popen.communicate(input=None, timeout=None)

与进程交互:将数据发送到标准输入。从标准输出和标准错误读取数据,直至到达文件末尾。等待进程终止。可选的input参数应为要发送到子进程的数据,如果没有数据应发送到子进程则为Noneinput的类型必须为字节,如果universal_newlinesTrue,则为字符串。

communicate()返回一个(stdout_data, stderr_data)元组。这些数据是字节形式,如果universal_newlinesTrue,则为字符串。

请注意,如果要将数据发送到进程的标准输入,则需要使用stdin=PIPE创建Popen对象。类似地,为了在结果元组中不只得到None,你还需要给予stdout=PIPE和/或stderr=PIPE

如果进程在timeout秒后未终止,则会引发TimeoutExpired异常。捕获此异常并重试通信将不会丢失任何输出。

如果超时过期,子进程不会被终止,因此为了正确清理一个良好的应用程序应该杀死子进程并完成通信:

proc = subprocess.Popen(...)
try:
    outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
    proc.kill()
    outs, errs = proc.communicate()

注意

注意读取的数据是缓存在内存中的,所以如果数据大小很大或者无限制请不要使用这个方法。

在版本3.3中更改:添加timeout

Popen.send_signal(signal)

发送信号signal 给子进程。

注意

在Windows上,SIGTERM是terminate()的别名。CTRL_C_EVENT和CTRL_BREAK_EVENT可以发送给启动参数creationflags 包含CREATE_NEW_PROCESS_GROUP 的进程。

Popen.terminate()

终止子进程。在Posix操作系统上,该方法发送SIGTERM给子进程。在Windows上,调用Win32 API函数TerminateProcess()来停止子进程。

Popen.kill()

杀死子进程。在Posix操作系统上,该函数发送SIGKILL给子进程。在Windows上,kill()terminate()的别名。

下面的属性也可以访问:

Popen.args

传递给Popenargs参数 —— 程序参数序列或单个字符串。

版本3.3中的新功能。

Popen.stdin

如果stdin参数为PIPE,则此属性是由open()返回的可写流对象。如果universal_newlines参数为True,则流是文本流,否则为字节流。如果stdin参数不是PIPE,则此属性为None

Popen.stdout

如果stdout参数为PIPE,则此属性是由open()返回的可读流对象。从流读取将提供子进程的输出。如果universal_newlines参数为True,则流是文本流,否则为字节流。如果stdout参数不是PIPE,则此属性为None

Popen.stderr

如果stderr参数为PIPE,则此属性是由open()返回的可读流对象。从流读取将提供从子进程的错误输出。如果universal_newlines参数为True,则流是文本流,否则为字节流。如果stderr参数不是PIPE,则此属性为None

警告

使用communicate()而不是.stdin.write.stdout.read.stderr.read来避免由于任何其他OS管道缓冲区填满和阻塞子进程而导致的死锁。

Popen.pid

子进程的进程ID。

请注意,如果将shell参数设置为True,那么这是生成的shell的进程ID。

Popen.returncode

poll()wait()(由communicate()间接设置)的子进程的返回码。None值表示进程尚未终止。

负值-N表示子进程被信号N终止(仅POSIX)。

17.5.4. Windows Popen的辅助类

STARTUPINFO类和以下常量仅在Windows上可用。

class subprocess.STARTUPINFO

部分支持Windows STARTUPINFO结构用于Popen创建。

dwFlags

确定在进程创建窗口时是否使用某些STARTUPINFO属性的位字段。

si = subprocess.STARTUPINFO()
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW
hStdInput

如果dwFlags指定STARTF_USESTDHANDLES,则此属性是进程的标准输入句柄。如果未指定STARTF_USESTDHANDLES,则标准输入的默认值为键盘缓冲区。

hStdOutput

如果dwFlags指定STARTF_USESTDHANDLES,则此属性是进程的标准输出句柄。否则,忽略该属性且默认的标准输出为控制台窗口的缓冲区。

hStdError

如果dwFlags指定STARTF_USESTDHANDLES,则此属性是进程的标准错误句柄。否则,忽略该属性且默认的标准错误输出为控制台窗口的缓冲区。

wShowWindow

如果dwFlags指定STARTF_USESHOWWINDOW,则此属性可以是nCmdShow参数中为ShowWindow函数指定的任何值,除了SW_SHOWDEFAULT否则,忽略该属性。

为此属性提供了SW_HIDEPopen使用shell=True调用时使用。

17.5.4.1. 常量

subprocess模块公开以下常量。

subprocess.STD_INPUT_HANDLE

标准输入设备。最初,这是控制台输入缓冲区,CONIN$

subprocess.STD_OUTPUT_HANDLE

标准输出设备。最初,这是活动控制台屏幕缓冲区,CONOUT$

subprocess.STD_ERROR_HANDLE

标准错误设备。最初,这是活动控制台屏幕缓冲区,CONOUT$

subprocess.SW_HIDE

隐藏窗口。另外一个窗口将被激活。

subprocess.STARTF_USESTDHANDLES

表示STARTUPINFO.hStdInputSTARTUPINFO.hStdOutputSTARTUPINFO.hStdError属性包含其他信息。

subprocess.STARTF_USESHOWWINDOW

表示STARTUPINFO.wShowWindow属性包含附加信息。

subprocess.CREATE_NEW_CONSOLE

新的进程将具有一个新的控制台,而不是继承它父进程的控制台(默认行为)。

subprocess.CREATE_NEW_PROCESS_GROUP

一个Popen creationflags参数,以指定将创建一个新进程组。在子进程上使用os.kill()时,此标志是必需的。

如果指定CREATE_NEW_CONSOLE,则忽略此标志。

17.5.5. 旧式的高级API

在Python 3.5之前,subprocess的高级API包含下面这三个函数。现在可以在许多情况下使用run(),但大量现有代码仍然调用这些函数。

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

执行args 描述的命令。等待命令完成,然后返回returncode属性。

这相当于:

run(...).returncode

(但不支持inputcheck参数)

上面显示的参数只是最常见的参数。完整的函数形式很大程度上与Popen构造函数相同 —— 除timeout之外,该函数的所有参数都直接传递给Popen接口。

注意

请勿使用stdout=PIPEstderr=PIPE调用用此函数。如果子进程生成足够的输出到一个管道并由于管道没有被读取而充满OS管道缓冲区,该子进程将阻塞。

在版本3.3中更改:添加timeout

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

执行带参数的命令。等待命令完成。如果返回码为零则返回,否则引发CalledProcessErrorCalledProcessError对象将返回码放在在returncode属性中。

这相当于:

run(..., check=True)

(除了不支持input参数)

上面显示的参数只是最常见的参数。完整的函数形式很大程度上与Popen构造函数相同 —— 除timeout之外,该函数的所有参数都直接传递给Popen接口。

注意

请勿使用stdout=PIPEstderr=PIPE调用此函数。如果子进程生成足够的输出到一个管道并由于管道没有被读取而充满OS管道缓冲区,该子进程将阻塞。

在版本3.3中更改:添加timeout

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

使用参数运行命令并返回其输出。

如果返回码非零,它将引发一个CalledProcessErrorCalledProcessError对象将返回码放在在returncode属性中,输出放在output属性中。

这相当于:

run(..., check=True, stdout=PIPE).stdout

上面显示的参数只是最常见的参数。完整的函数形式很大程度上与Popen构造函数相同 —— 该函数的大部分参数都直接传递给Popen接口。但是,不支持显式传递input=None来继承父进程的标准输入文件句柄。

默认情况下,此函数将以编码的字节返回数据。输出数据的实际编码可以取决于被调用的命令,因此对文本的解码通常需要在应用程序级处理。

可通过将universal_newlines设置为True来覆盖此行为,如上述常用参数中所述。

要在结果中捕获标准错误,请使用stderr=subprocess.STDOUT

>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     shell=True)
'ls: non_existent_file: No such file or directory\n'

版本3.1中的新功能。

在版本3.3中更改:添加timeout

在版本3.4中更改:添加对input关键字参数的支持。

17.5.6. 使用subprocess模块替换旧的函数

在本小节中,“a变为b”的意思是b可以作为a的一种替换使用。

注意

如果无法找到执行的程序,则本节中的所有“a”函数都会失败(或多或少); “b”替换则引发OSError

此外,如果请求的操作产生非零返回代码,则使用check_output()的替换将失败并显示CalledProcessError输出仍然可以在引发的异常的output属性中访问。

在以下示例中,我们假设相关函数已从subprocess模块导入。

17.5.6.1. 替换/bin/sh shell反引号

output=`mycmd myarg`

变为:

output = check_output(["mycmd", "myarg"])

17.5.6.2. 替换shell管道

output=`dmesg | grep hda`

变为:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

在p2之后调用p1.stdout.close() 是非常重要的,这样,如果p2在 p1之前退出p1可以收到一个SIGPIPE信号。

另外一种方法,对于可信任的输入,也可以直接使用shell自己对管道的支持:

output=`dmesg | grep hda`

变为:

output=check_output("dmesg | grep hda", shell=True)

17.5.6.3. 替换os.system()

sts = os.system("mycmd" + " myarg")
# becomes
sts = call("mycmd" + " myarg", shell=True)

注意:

  • 通常不需要通过shell调用程序

更真实的例子可能像这样:

try:
    retcode = call("mycmd" + " myarg", shell=True)
    if retcode < 0:
        print("Child was terminated by signal", -retcode, file=sys.stderr)
    else:
        print("Child returned", retcode, file=sys.stderr)
except OSError as e:
    print("Execution failed:", e, file=sys.stderr)

17.5.6.4. 替换os.spawn系列

P_NOWAIT 示例:

pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
==>
pid = Popen(["/bin/mycmd", "myarg"]).pid

P_WAIT 示例:

retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
==>
retcode = call(["/bin/mycmd", "myarg"])

向量示例:

os.spawnvp(os.P_NOWAIT, path, args)
==>
Popen([path] + args[1:])

环境变量示例:

os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
==>
Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})

17.5.6.5. 替换os.popen()os.popen2()os.popen3()

(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
(child_stdin,
 child_stdout,
 child_stderr) = os.popen3(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin,
 child_stdout,
 child_stderr) = (p.stdin, p.stdout, p.stderr)
(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
==>
p = Popen(cmd, shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)

返回码的处理可以转换成下面的方式:

pipe = os.popen(cmd, 'w')
...
rc = pipe.close()
if rc is not None and rc >> 8:
    print("There were some errors")
==>
process = Popen(cmd, stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
    print("There were some errors")

17.5.6.6. 替换popen2模块中的函数

注意

如果popen2函数的cmd参数是字符串,则通过/bin/sh执行该命令。如果是列表,则直接执行命令。

(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
==>
p = Popen("somestring", shell=True, bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)
(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
==>
p = Popen(["mycmd", "myarg"], bufsize=bufsize,
          stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)

popen2.Popen3popen2.Popen4工作方式基本上类似于subprocess.Popen,除了以下几点:

  • Popen如果执行失败,则引发异常。
  • capturestderr 参数替换成stderr 参数。
  • stdin=PIPEstdout=PIPE必须指定。
  • popen2默认关闭所有文件描述器,但你必须用Popen指定close_fds=True以保证在所有平台或过去的Python版本上的行为。

17.5.7. 传统Shell调用函数

该模块还提供以下的来自2.x commands模块的旧式函数。这些操作隐式调用系统shell,并且上述关于安全性和异常处理一致性的保证都不对这些函数有效。

subprocess.getstatusoutput(cmd)

返回在shell中执行cmd(status, output)

Popen.check_output()在shell中执行字符串cmd,并返回一个二元组(status, output)使用通用换行模式;有关详细信息,请参阅常用参数上的说明。

从输出中去除尾部换行符。可以根据C函数wait()的规则解释命令的退出状态。例如:

>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
>>> subprocess.getstatusoutput('cat /bin/junk')
(256, 'cat: /bin/junk: No such file or directory')
>>> subprocess.getstatusoutput('/bin/junk')
(256, 'sh: /bin/junk: not found')

可用的平台:POSIX&Windows

在版本3.3.4中更改:添加了Windows的支持

subprocess.getoutput(cmd)

返回在shell中执行cmd的输出(标准输出和标准错误)。

类似getstatusoutput(),除了退出状态被忽略,返回值是一个包含命令输出的字符串。例如:

>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'

可用的平台:POSIX&Windows

在版本3.3.4中更改:添加了Windows的支持

17.5.8.

17.5.8.1. 将参数序列转换为Windows上的字符串

在 Windows 上,args 序列被转换为一个可以使用下面的规则(MS C 的运行时规则)解析的字符串:

  1. 参数通过空白符分隔,空白符可以是空格或者制表符。
  2. 由双引号括起来的字符串将被解释为单个参数,而不考虑其中包含的空格。引用的字符串可以嵌入参数中。
  3. 一个前面带有反斜线的双引号解释为一个双引号字面量。
  4. 反斜线按字面量解释,除非它们后面紧跟着一个双引号。
  5. 如果反斜杠紧跟在双引号之前,则每对反斜杠都被解释为字面值反斜杠。如果反斜杠的数量为奇数,则最后一个反斜杠转义为下一个双引号,如规则3所述。

另可参阅

shlex
提供解析和转义命令行的功能的模块。