subprocess — 子流程管理 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/subprocess
跳转至:导航、​搜索

subprocess — 子流程管理

源代码: :source:`Lib/subprocess.py`



subprocess 模块允许您生成新进程,连接到它们的输入/输出/错误管道,并获取它们的返回代码。 该模块打算替换几个较旧的模块和功能:

os.system
os.spawn*

有关如何使用 subprocess 模块替换这些模块和功能的信息,请参见以下部分。

也可以看看

PEP 324 – PEP 提出子流程模块


使用 子进程 模块

调用子进程的推荐方法是将 run() 函数用于它可以处理的所有用例。 对于更高级的用例,可以直接使用底层的 Popen 接口。

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

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, **other_popen_kwargs)

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

上面显示的参数只是最常见的参数,在下面的 常用参数 中进行了描述(因此在缩写签名中使用了仅关键字表示法)。 完整的函数签名与 Popen 构造函数的签名基本相同 - 此函数的大部分参数都传递到该接口。 (timeout、input、check和capture_output不是。)

如果 capture_output 为真,则将捕获 stdout 和 stderr。 使用时,内部 Popen 对象会自动使用 stdout=PIPE 和 stderr=PIPE 创建。 stdout 和 stderr 参数不能与 capture_output 同时提供。 如果您希望捕获两个流并将其合并为一个,请使用 stdout=PIPE 和 stderr=STDOUT 而不是 capture_output。

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

input 参数被传递给 Popen.communicate(),从而传递给子进程的标准输入。 如果使用它,它必须是一个字节序列,如果指定了 encoding 或 errors 或 text 为真,则它必须是一个字符串。 使用时,内部 Popen 对象会自动使用 stdin=PIPE 创建,并且可能不会使用 stdin 参数。

如果 check 为真,并且进程以非零退出代码退出,则会引发 CalledProcessError 异常。 该异常的属性包含参数、退出代码以及 stdout 和 stderr(如果它们被捕获)。

如果指定了 encoding 或 errors,或者 text 为真,则使用指定的 编码以文本模式打开 stdin、stdout 和 stderr 的文件对象 和 错误 或 io.TextIOWrapper 默认值。 universal_newlines 参数等效于 text 并提供向后兼容性。 默认情况下,文件对象以二进制模式打开。

如果 env 不是 None,则必须是定义新进程的环境变量的映射; 这些用于代替继承当前进程环境的默认行为。 它直接传递给 Popen。

例子:

>>> 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"], capture_output=True)
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', stderr=b'')

3.5 版中的新功能。

3.6 版更改: 添加 编码 和 错误 参数

3.7 版本变更: 增加了 text 参数,作为 universal_newlines 的更易理解的别名。 添加了 capture_output 参数。

class subprocess.CompletedProcess

run() 的返回值,代表一个已经完成的进程。

args

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

returncode

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

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

stdout

从子进程捕获标准输出。 如果使用编码、错误或 text=True 调用 run(),则为字节序列或字符串。 None 如果标准输出未被捕获。

如果您使用 stderr=subprocess.STDOUT 运行该进程,则 stdout 和 stderr 将在此属性中组合,而 stderr 将是 None。

stderr

从子进程捕获 stderr。 如果使用编码、错误或 text=True 调用 run(),则为字节序列或字符串。 None 如果未捕获 stderr。

check_returncode()

如果 returncode 非零,则引发 CalledProcessError。

3.5 版中的新功能。

subprocess.DEVNULL

可用作 Popen 的 stdin、stdout 或 stderr 参数的特殊值,并指示特殊文件 os .devnull 将被使用。

3.3 版中的新功能。

subprocess.PIPE
可用作 Popen 的 stdin、stdout 或 stderr 参数的特殊值,并指示标准流的管道应该被打开。 对 Popen.communicate() 最有用。
subprocess.STDOUT
可用作 Popen 的 stderr 参数的特殊值,并指示标准错误应进入与标准输出相同的句柄。
exception subprocess.SubprocessError

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

3.3 版中的新功能。

exception subprocess.TimeoutExpired

SubprocessError 的子类,在等待子进程时超时到期时引发。

cmd

用于生成子进程的命令。

timeout

以秒为单位的超时。

output

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

stdout

输出别名,与 stderr 对称。

stderr

子进程的 Stderr 输出,如果它被 run() 捕获。 否则,None。

3.3 版中的新功能。

3.5 版更改:添加了 stdout 和 stderr 属性

exception subprocess.CalledProcessError

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

returncode

子进程的退出状态。 如果进程因信号而退出,这将是负信号数。

cmd

用于生成子进程的命令。

output

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

stdout

输出别名,与 stderr 对称。

stderr

子进程的 Stderr 输出,如果它被 run() 捕获。 否则,None。

3.5 版更改:添加了 stdout 和 stderr 属性

常用参数

为了支持各种用例,Popen 构造函数(和便利函数)接受大量可选参数。 对于大多数典型用例,其中许多参数可以安全地保留为默认值。 最常需要的参数是:

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

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

如果指定了 encoding 或 errors,或者 text(也称为 universal_newlines)为真,则文件对象 stdin[ X151X]、stdout 和 stderr 将使用 encoding 和 errors 在调用中指定或默认值以文本模式打开X312X]io.TextIOWrapper。

对于 stdin,输入中的行结束字符 '\n' 将被转换为默认的行分隔符 os.linesep。 对于 stdout 和 stderr,输出中的所有行尾都将转换为 '\n'。 有关更多信息,请参阅 io.TextIOWrapper 类的文档,当其构造函数的 newline 参数为 None 时。

如果不使用文本模式,stdin、stdout 和 stderr 将作为二进制流打开。 不执行编码或行结束转换。

3.6 新功能: 添加 编码 和 错误 参数。


3.7 新功能: 添加 text 参数作为 universal_newlines 的别名。


笔记

文件对象 Popen.stdin、Popen.stdout 和 Popen.stderr 的换行符属性不会被 Popen.communicate()[ X159X] 方法。


如果shell为True,指定的命令将通过shell执行。 如果您主要使用 Python 来增强它在大多数系统 shell 上提供的控制流,并且仍然希望方便地访问其他 shell 功能,例如 shell 管道、文件名通配符、环境变量扩展和 [X268X 的扩展,这将非常有用] 到用户的主目录。 但是,请注意 Python 本身提供了许多类似 shell 的功能的实现(特别是 glob、fnmatch、os.walk()、os .path.expandvars()、os.path.expanduser() 和 shutil)。

3.3 版本变更:当 universal_newlines 为 True 时,类使用编码 locale.getpreferredencoding(False) 而不是 [ X167X]。 有关此更改的更多信息,请参阅 io.TextIOWrapper 类。


笔记

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


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


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=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None, text=None)

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

args 应该是一系列程序参数,或者是单个字符串或 类路径对象 。 默认情况下,如果 args 是一个序列,则要执行的程序是 args 中的第一项。 如果 args 是字符串,则解释取决于平台,如下所述。 请参阅 shell 和 executable 参数以了解与默认行为的其他差异。 除非另有说明,建议将 args 作为序列传递。

将一些参数作为序列传递给外部程序的示例是:

Popen(["/usr/bin/git", "commit", "-m", "Fixes a bug."])

在 POSIX 上,如果 args 是一个字符串,则该字符串被解释为要执行的程序的名称或路径。 但是,这只能在不向程序传递参数的情况下完成。

笔记

如何将 shell 命令分解为一系列参数可能并不明显,尤其是在复杂的情况下。 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() 对字符串进行操作。

在 3.6 版更改:args 参数接受一个 path-like object 如果 shell 是 False 和一个包含POSIX 上的类似路径的对象。

在 3.8 版更改:args 参数接受一个 path-like object 如果 shell 是 False 和一个包含Windows 上的字节和类似路径的对象。

shell 参数(默认为 False)指定是否使用 shell 作为程序执行。 如果 shell 是 True,建议将 args 作为字符串而不是序列传递。

在带有 shell=True 的 POSIX 上,shell 默认为 /bin/sh。 如果 args 是字符串,则该字符串指定要通过 shell 执行的命令。 这意味着字符串的格式必须与在 shell 提示符下键入时完全相同。 例如,这包括引用或反斜杠转义其中包含空格的文件名。 如果 args 是一个序列,则第一项指定命令字符串,任何附加项都将被视为 shell 本身的附加参数。 也就是说, Popen 相当于:

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

在带有 shell=True 的 Windows 上,COMSPEC 环境变量指定默认 shell。 在 Windows 上你唯一需要指定 shell=True 的时候是当你想要执行的命令被内置到 shell 中时(例如 dir 或 copy)。 您不需要 shell=True 来运行批处理文件或基于控制台的可执行文件。

笔记

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

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

  • 0 表示无缓冲(读和写是一个系统调用,可以短返回)

  • 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。

3.6 版更改:executable 参数接受 POSIX 上的 类路径对象 。

在 3.8 版更改:executable 参数在 Windows 上接受一个字节和 类路径对象 。

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

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

警告

preexec_fn 参数在应用程序中存在线程的情况下使用是不安全的。 在调用 exec 之前,子进程可能会死锁。 如果您必须使用它,请保持微不足道! 尽量减少您调用的库数量。

笔记

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

3.8 版更改: 子解释器不再支持 [X37X]preexec_fn 参数。 在子解释器中使用该参数会引发 RuntimeError。 新限制可能会影响部署在 mod_wsgi、uWSGI 和其他嵌入式环境中的应用程序。

如果 close_fds 为真,除 0、1 和 2 之外的所有文件描述符都将在子进程执行前关闭。 否则,当 close_fds 为 false 时,文件描述符遵循其可继承标志,如 文件描述符的继承 中所述。

在 Windows 上,如果 close_fds 为真,则子进程不会继承任何句柄,除非在 STARTUPINFO.lpAttributeList 的 handle_list 元素中显式传递,或通过标准句柄重定向。

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

3.7 版更改: 在 Windows 上,重定向标准句柄时 close_fds 的默认值从 False 更改为 True。 现在可以在重定向标准句柄时将 close_fds 设置为 True。

pass_fds 是一个可选的文件描述符序列,用于在父级和子级之间保持打开状态。 提供任何 pass_fds 强制 close_fds 为 True。 (仅限 POSIX)

3.2 版更改: 添加了 pass_fds 参数。

如果 cwd 不是 None,则函数在执行子进程之前将工作目录更改为 cwd。 cwd 可以是字符串、字节或 类似路径的 对象。 特别是,如果可执行路径是相对路径,该函数会查找相对于 cwd 的 executable(或 args 中的第一项)。

在 3.6 版更改:cwd 参数接受 POSIX 上的 类路径对象 。

在 3.7 版中更改:cwd 参数接受 Windows 上的 类路径对象 。

3.8 版更改:cwd 参数在 Windows 上接受字节对象。

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

3.2 版更改:添加了 restore_signals。

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

3.2 版更改:添加了 start_new_session。

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

笔记

如果指定,env 必须提供程序执行所需的任何变量。 在 Windows 上,为了运行 并行程序集 ,指定的 env 必须 包含有效的 SystemRoot ]。

如果指定了 encoding 或 errors,或者 text 为真,则文件对象 stdin、stdout 和 [ X134X]stderr 以文本模式打开,具有指定的编码和 errors,如上文 常用参数 中所述。 universal_newlines 参数等效于 text 并提供向后兼容性。 默认情况下,文件对象以二进制模式打开。

3.6 版新功能:添加了 encoding 和 errors。

3.7 版新功能:添加了 text 作为 universal_newlines 的更具可读性的别名。

如果给定,startupinfo 将是一个 STARTUPINFO 对象,它被传递给底层的 CreateProcess 函数。 creationflags,如果给定,可以是以下一个或多个标志:

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

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

3.2 版更改: 添加了上下文管理器支持。

3.6 版更改:Popen 析构函数现在在子进程仍在运行时发出 ResourceWarning 警告。

3.8 版更改: Popen 在某些情况下可以使用 os.posix_spawn() 以获得更好的性能。 在适用于 Linux 的 Windows 子系统和 QEMU 用户仿真上,使用 os.posix_spawn() 的 Popen 构造函数不再引发程序丢失等错误的异常,但子进程失败并返回非零 returncode[ X225X]。


例外

在新程序开始执行之前,子进程中引发的异常将在父进程中重新引发。

最常见的异常是 OSError。 例如,在尝试执行不存在的文件时会发生这种情况。 应用程序应该为 OSError 异常做好准备。

如果使用无效参数调用 Popen,则会引发 ValueError。

check_call() 和 check_output() 将引发 CalledProcessError 如果被调用进程返回非零返回代码。

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

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

3.3 新功能: 添加了 SubprocessError 基类。


安全注意事项

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

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


弹出对象

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

Popen.poll()
检查子进程是否已终止。 设置并返回 returncode 属性。 否则,返回 None。
Popen.wait(timeout=None)

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

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

笔记

这将在使用 stdout=PIPE 或 stderr=PIPE 时死锁,并且子进程向管道生成足够的输出,从而阻止等待 OS 管道缓冲区接受更多数据。 使用管道时使用 Popen.communicate() 来避免这种情况。

笔记

该函数是使用繁忙循环(非阻塞调用和短暂睡眠)实现的。 使用 asyncio 模块进行异步等待:参见 asyncio.create_subprocess_exec。

3.3 版更改:添加了 timeout。

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

与进程交互:将数据发送到标准输入。 从 stdout 和 stderr 读取数据,直到到达文件结尾。 等待进程终止并设置 returncode 属性。 可选的 input 参数应该是要发送到子进程的数据,或者 None,如果没有数据应该发送到子进程。 如果流以文本模式打开,则 input 必须是字符串。 否则,它必须是字节。

communicate() 返回一个元组 (stdout_data, stderr_data)。 如果流以文本模式打开,则数据将是字符串; 否则,字节。

请注意,如果要将数据发送到进程的标准输入,则需要使用 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

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

3.3 版中的新功能。

Popen.stdin
如果 stdin 参数是 PIPE,则此属性是 open() 返回的可写流对象。 如果指定了 encoding 或 errors 参数或 universal_newlines 参数是 True,则流为文本流,否则为字节溪流。 如果 stdin 参数不是 PIPE,则此属性为 None。
Popen.stdout
如果 stdout 参数是 PIPE,则此属性是 open() 返回的可读流对象。 从流中读取提供了子进程的输出。 如果指定了 encoding 或 errors 参数或 universal_newlines 参数是 True,则流为文本流,否则为字节溪流。 如果 stdout 参数不是 PIPE,则此属性为 None。
Popen.stderr
如果 stderr 参数是 PIPE,则此属性是 open() 返回的可读流对象。 从流中读取提供了子进程的错误输出。 如果指定了 encoding 或 errors 参数或 universal_newlines 参数是 True,则流为文本流,否则为字节溪流。 如果 stderr 参数不是 PIPE,则此属性为 None。

警告

使用 communicate() 而不是 .stdin.write, .stdout.read 或 .stderr.read 以避免由于任何原因造成的死锁其他操作系统管道缓冲区填满并阻塞子进程。


Popen.pid

子进程的进程 ID。

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

Popen.returncode

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

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


Windows Popen 助手

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

class subprocess.STARTUPINFO(*, dwFlags=0, hStdInput=None, hStdOutput=None, hStdError=None, wShowWindow=0, lpAttributeList=None)

Windows STARTUPINFO 结构的部分支持用于 Popen 创建。 可以通过将它们作为仅关键字参数传递来设置以下属性。

3.7 版更改: 添加了仅关键字参数支持。

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,则该属性可以是可以在 ShowWindow 函数的 nCmdShow 参数中指定的任何值,除了对于 SW_SHOWDEFAULT。 否则,该属性将被忽略。

SW_HIDE 是为此属性提供的。 当使用 shell=True 调用 Popen 时使用。

lpAttributeList

STARTUPINFOEX 中给出的用于进程创建的附加属性字典,请参阅 UpdateProcThreadAttribute。

支持的属性:

句柄列表

将被继承的句柄序列。 close_fds 如果非空必须为真。

当传递给 Popen 构造函数时,句柄必须暂时由 os.set_handle_inheritable() 继承,否则 OSError 将引发 Windows 错误 [ X196X] (87)。

警告

在多线程进程中,当将此功能与对继承所有句柄(例如 os.system())的其他进程创建函数的并发调用结合使用时,请小心避免泄漏标记为可继承的句柄。 这也适用于标准句柄重定向,它临时创建可继承的句柄。

3.7 版中的新功能。

窗口常量

subprocess 模块公开以下常量。

subprocess.STD_INPUT_HANDLE
标准输入设备。 最初,这是控制台输入缓冲区,CONIN$。
subprocess.STD_OUTPUT_HANDLE
标准输出设备。 最初,这是活动的控制台屏幕缓冲区,CONOUT$。
subprocess.STD_ERROR_HANDLE
标准错误设备。 最初,这是活动的控制台屏幕缓冲区,CONOUT$。
subprocess.SW_HIDE
隐藏窗口。 另一个窗口将被激活。
subprocess.STARTF_USESTDHANDLES
指定 STARTUPINFO.hStdInput、STARTUPINFO.hStdOutput 和 STARTUPINFO.hStdError 属性包含附加信息。
subprocess.STARTF_USESHOWWINDOW
指定 STARTUPINFO.wShowWindow 属性包含附加信息。
subprocess.CREATE_NEW_CONSOLE
新进程有一个新的控制台,而不是继承其父级的控制台(默认)。
subprocess.CREATE_NEW_PROCESS_GROUP

Popen creationflags 参数指定将创建新进程组。 该标志对于在子进程上使用 os.kill() 是必需的。

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

subprocess.ABOVE_NORMAL_PRIORITY_CLASS

Popen creationflags 参数指定新进程将具有高于平均优先级。

3.7 版中的新功能。

subprocess.BELOW_NORMAL_PRIORITY_CLASS

Popen creationflags 参数指定新进程将具有低于平均优先级。

3.7 版中的新功能。

subprocess.HIGH_PRIORITY_CLASS

Popen creationflags 参数指定新进程将具有高优先级。

3.7 版中的新功能。

subprocess.IDLE_PRIORITY_CLASS

Popen creationflags 参数指定新进程将具有空闲(最低)优先级。

3.7 版中的新功能。

subprocess.NORMAL_PRIORITY_CLASS

Popen creationflags 参数指定新进程将具有正常优先级。 (默认)

3.7 版中的新功能。

subprocess.REALTIME_PRIORITY_CLASS

Popen creationflags 参数指定新进程将具有实时优先级。 您几乎不应该使用 REALTIME_PRIORITY_CLASS,因为这会中断管理鼠标输入、键盘输入和后台磁盘刷新的系统线程。 此类适用于直接与硬件“对话”或执行应具有有限中断的简短任务的应用程序。

3.7 版中的新功能。

subprocess.CREATE_NO_WINDOW

Popen creationflags 参数指定新进程不会创建窗口。

3.7 版中的新功能。

subprocess.DETACHED_PROCESS

Popen creationflags 参数指定新进程不会继承其父进程的控制台。 此值不能与 CREATE_NEW_CONSOLE 一起使用。

3.7 版中的新功能。

subprocess.CREATE_DEFAULT_ERROR_MODE

Popen creationflags 参数指定新进程不继承调用进程的错误模式。 相反,新进程获得默认错误模式。 此功能对于在禁用硬错误的情况下运行的多线程 shell 应用程序特别有用。

3.7 版中的新功能。

subprocess.CREATE_BREAKAWAY_FROM_JOB

Popen creationflags 参数指定新进程不与作业关联。

3.7 版中的新功能。


较旧的高级 API

在 Python 3.5 之前,这三个函数组成了子进程的高级 API。 您现在可以在许多情况下使用 run(),但许多现有代码调用这些函数。

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

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

需要捕获 stdout 或 stderr 的代码应该使用 run() 代替:

run(...).returncode

要抑制 stdout 或 stderr,请提供 DEVNULL 值。

上面显示的参数只是一些常见的参数。 完整的函数签名与 Popen 构造函数的签名相同 - 此函数将除 timeout 以外的所有提供的参数直接传递到该接口。

笔记

请勿将 stdout=PIPE 或 stderr=PIPE 与此功能一起使用。 如果子进程生成足够的输出到管道以填充操作系统管道缓冲区,则子进程将阻塞,因为管道未被读取。

3.3 版更改:添加了 timeout。

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

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

需要捕获 stdout 或 stderr 的代码应该使用 run() 代替:

run(..., check=True)

要抑制 stdout 或 stderr,请提供 DEVNULL 值。

上面显示的参数只是一些常见的参数。 完整的函数签名与 Popen 构造函数的签名相同 - 此函数将除 timeout 以外的所有提供的参数直接传递到该接口。

笔记

请勿将 stdout=PIPE 或 stderr=PIPE 与此功能一起使用。 如果子进程生成足够的输出到管道以填充操作系统管道缓冲区,则子进程将阻塞,因为管道未被读取。

3.3 版更改:添加了 timeout。

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, cwd=None, encoding=None, errors=None, universal_newlines=None, timeout=None, text=None, **other_popen_kwargs)

运行带参数的命令并返回其输出。

如果返回码不为零,则会引发 CalledProcessError。 CalledProcessError 对象将在 returncode 属性中包含返回代码,在 output 属性中包含任何输出。

这相当于:

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

上面显示的参数只是一些常见的参数。 完整的函数签名与 run() 的签名基本相同 - 大多数参数直接传递到该接口。 存在与 run() 行为的 API 偏差:传递 input=None 将与 input=b(或 input=,取决于其他参数)表现相同,而不是使用父级的标准输入文件句柄。

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

此行为可以通过将 text、encoding、errors 或 universal_newlines 设置为 True 来覆盖,如[ X155X]常用参数和run()。

要同时捕获结果中的标准错误,请使用 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 关键字参数的支持。

3.6 版更改:添加了 encoding 和 errors。 有关详细信息,请参阅 run()。

3.7 版新功能:添加了 text 作为 universal_newlines 的更具可读性的别名。


用 子进程 模块替换旧函数

在本节中,“a 变成 b”意味着 b 可以用作 a 的替代。

笔记

如果找不到执行的程序,本节中的所有“a”函数都会以静默方式失败(或多或少); “b”替换引发 OSError。

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


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

替换 /bin/sh shell 命令替换

output=$(mycmd myarg)

变成:

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

更换外壳管道

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)

替换 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)

替换 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"})

替换 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")

替换 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.Popen3 和 popen2.Popen4 基本上作为 subprocess.Popen 工作,除了:

  • 如果执行失败,Popen 会引发异常。
  • capturestderr 参数被替换为 stderr 参数。
  • 必须指定 stdin=PIPE 和 stdout=PIPE。
  • popen2 默认关闭所有文件描述符,但您必须指定 close_fds=True 和 Popen 以保证在所有平台或过去的 Python 版本上都有这种行为。


传统 Shell 调用函数

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

subprocess.getstatusoutput(cmd)

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

在带有 Popen.check_output() 的 shell 中执行字符串 cmd 并返回一个二元组 (exitcode, output)。 使用语言环境编码; 有关更多详细信息,请参阅 常用参数 上的注释。

从输出中删除尾随换行符。 命令的退出码可以解释为子进程的返回码。 例子:

>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
>>> subprocess.getstatusoutput('cat /bin/junk')
(1, 'cat: /bin/junk: No such file or directory')
>>> subprocess.getstatusoutput('/bin/junk')
(127, 'sh: /bin/junk: not found')
>>> subprocess.getstatusoutput('/bin/kill $$')
(-15, '')

在 3.3.4 版更改:添加了 Windows 支持。

该函数现在返回 (exitcode, output) 而不是 (status, output) ,就像它在 Python 3.3.3 及更早版本中所做的那样。 exitcode 与 returncode 具有相同的值。

subprocess.getoutput(cmd)

返回在 shell 中执行 cmd 的输出(stdout 和 stderr)。

与 getstatusoutput() 类似,除了退出代码被忽略并且返回值是包含命令输出的字符串。 例子:

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

3.3.4 版更改: 增加了 Windows 支持


笔记

在 Windows 上将参数序列转换为字符串

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

  1. 参数由空格分隔,空格或制表符。
  2. 被双引号包围的字符串被解释为单个参数,而不管其中包含的空格。 带引号的字符串可以嵌入到参数中。
  3. 以反斜杠开头的双引号被解释为文字双引号。
  4. 反斜杠按字面解释,除非它们紧跟在双引号之前。
  5. 如果反斜杠紧跟在双引号之前,则每一对反斜杠都被解释为文字反斜杠。 如果反斜杠的数量是奇数,则最后一个反斜杠会转义下一个双引号,如规则 3 中所述。

也可以看看

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