subprocess
- 子进程管理¶
**源代码:** Lib/subprocess.py
subprocess
模块允许您生成新进程,连接到它们的输入/输出/错误管道,并获取它们的返回代码。此模块旨在替换几个旧的模块和函数。
os.system
os.spawn*
有关如何使用 subprocess
模块替换这些模块和函数的信息,请参阅以下部分。
另请参阅
PEP 324 - 提出 subprocess 模块的 PEP
可用性:不支持 Emscripten,不支持 WASI。
此模块在 WebAssembly 平台 wasm32-emscripten
和 wasm32-wasi
上不可用或无法工作。有关更多信息,请参阅 WebAssembly 平台。
使用 subprocess
模块¶
调用子进程的推荐方法是针对所有可以处理的用例使用 run()
函数。对于更高级的用例,可以直接使用底层的 Popen
接口。
- 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 为 true,则将捕获 stdout 和 stderr。使用时,内部
Popen
对象会自动创建,并将 stdout 和 stderr 都设置为PIPE
。stdout 和 stderr 参数不能与 capture_output 同时提供。如果您希望捕获并将两个流合并为一个,请将 stdout 设置为PIPE
,并将 stderr 设置为STDOUT
,而不是使用 capture_output。可以以秒为单位指定 timeout,它会在内部传递给
Popen.communicate()
。如果超时,子进程将被杀死并等待。在子进程终止后,将重新引发TimeoutExpired
异常。在许多平台 API 上,初始进程创建本身不能被中断,因此您不能保证在至少经过进程创建所需的时间之后才会看到超时异常。input 参数被传递给
Popen.communicate()
,因此也被传递给子进程的标准输入。如果使用它,它必须是一个字节序列,或者如果指定了 encoding 或 errors 或 text 为 true,则它必须是一个字符串。当使用时,内部的Popen
对象会自动创建,并将 stdin 设置为PIPE
,并且不能同时使用 stdin 参数。如果 check 为 true,并且进程以非零退出代码退出,则会引发
CalledProcessError
异常。该异常的属性包含参数、退出代码以及标准输出和标准错误(如果它们被捕获)。如果指定了 encoding 或 errors,或者 text 为 true,则使用指定的 encoding 和 errors 或
io.TextIOWrapper
默认值以文本模式打开标准输入、标准输出和标准错误的文件对象。universal_newlines 参数等效于 text,是为了向后兼容而提供的。默认情况下,文件对象以二进制模式打开。如果 env 不是
None
,则它必须是一个映射,用于定义新进程的环境变量;这些变量将取代继承当前进程环境的默认行为。它被直接传递给Popen
。此映射可以是任何平台上的 str 到 str,也可以是 POSIX 平台上的 bytes 到 bytes,类似于os.environ
或os.environb
。例子
>>> 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 版更改: 添加了 encoding 和 errors 参数
3.7 版更改: 添加了 text 参数,作为 universal_newlines 更易理解的别名。添加了 capture_output 参数。
3.12 版更改: 更改了 Windows shell 对
shell=True
的搜索顺序。当前目录和%PATH%
被替换为%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,将名为cmd.exe
的恶意程序放入当前目录将不再起作用。
- class subprocess.CompletedProcess¶
run()
的返回值,表示已完成的进程。- args¶
用于启动进程的参数。这可以是一个列表或一个字符串。
- returncode¶
子进程的退出状态。通常,退出状态 0 表示它已成功运行。
负值
-N
表示子进程被信号N
终止(仅限 POSIX)。
- stdout¶
从子进程捕获的标准输出。一个字节序列,或者如果使用编码、错误或 text=True 调用
run()
,则为字符串。如果未捕获标准输出,则为None
。如果您使用
stderr=subprocess.STDOUT
运行进程,则标准输出和标准错误将组合在此属性中,并且stderr
将为None
。
- check_returncode()¶
如果
returncode
不为零,则引发CalledProcessError
。
3.5 版新增。
- subprocess.DEVNULL¶
特殊值,可用作
Popen
的 stdin、stdout 或 stderr 参数,表示将使用特殊文件os.devnull
。3.3 版新增。
- subprocess.PIPE¶
特殊值,可用作
Popen
的 stdin、stdout 或 stderr 参数,表示应打开到标准流的管道。与Popen.communicate()
一起使用最有用。
- exception subprocess.SubprocessError¶
此模块中所有其他异常的基类。
3.3 版新增。
- exception subprocess.TimeoutExpired¶
SubprocessError
的子类,在等待子进程时超时到期时引发。- cmd¶
用于生成子进程的命令。
- timeout¶
超时时间(以秒为单位)。
- output¶
如果子进程的输出被
run()
或check_output()
捕获,则返回该输出。否则,返回None
。无论text=True
设置如何,只要捕获到任何输出,它都始终是bytes
类型。如果没有观察到输出,它可能会保持为None
而不是b''
。
- stderr¶
如果子进程的标准错误输出被
run()
捕获,则返回该输出。否则,返回None
。无论text=True
设置如何,只要捕获到任何标准错误输出,它都始终是bytes
类型。如果没有观察到标准错误输出,它可能会保持为None
而不是b''
。
3.3 版新增。
在 3.5 版更改: 添加了 stdout 和 stderr 属性
- exception subprocess.CalledProcessError¶
SubprocessError
的子类,当由check_call()
、check_output()
或run()
(使用check=True
)运行的进程返回非零退出状态时引发。- returncode¶
子进程的退出状态。如果进程因信号而退出,这将是负信号编号。
- cmd¶
用于生成子进程的命令。
- output¶
如果子进程的输出被
run()
或check_output()
捕获,则返回该输出。否则,返回None
。
在 3.5 版更改: 添加了 stdout 和 stderr 属性
常用参数¶
为了支持各种用例,Popen
构造函数(以及便捷函数)接受大量可选参数。对于大多数典型用例,其中许多参数可以安全地保留其默认值。最常用的参数是
args 是所有调用都需要的,它应该是一个字符串,或者是一个程序参数序列。通常首选提供参数序列,因为它允许模块处理任何需要的参数转义和引用(例如,允许文件名中包含空格)。如果传递单个字符串,则 shell 必须为
True
(见下文),否则该字符串必须仅命名要执行的程序,而不指定任何参数。stdin、stdout 和 stderr 分别指定已执行程序的标准输入、标准输出和标准错误文件句柄。有效值为
None
、PIPE
、DEVNULL
、现有文件描述符(正整数)和具有有效文件描述符的现有 文件对象。使用默认设置None
时,不会发生重定向。PIPE
表示应创建到子进程的新管道。DEVNULL
表示将使用特殊文件os.devnull
。此外,stderr 可以是STDOUT
,这表示来自子进程的标准错误数据应捕获到与 stdout 相同的文件句柄中。如果指定了 encoding 或 errors,或者 text(也称为 universal_newlines)为 true,则文件对象 stdin、stdout 和 stderr 将使用调用中指定的 encoding 和 errors 或
io.TextIOWrapper
的默认值以文本模式打开。对于 stdin,输入中的行尾字符
'\n'
将转换为默认行分隔符os.linesep
。对于 stdout 和 stderr,输出中的所有行尾都将转换为'\n'
。有关更多信息,请参阅io.TextIOWrapper
类的文档,其中构造函数的 newline 参数为None
。如果不使用文本模式,则 stdin、stdout 和 stderr 将作为二进制流打开。不执行编码或行尾转换。
在 3.6 版更改: 添加了 encoding 和 errors 参数。
在 3.7 版更改: 添加了 text 参数作为 universal_newlines 的别名。
注意
文件对象
Popen.stdin
、Popen.stdout
和Popen.stderr
的 newlines 属性不会被Popen.communicate()
方法更新。如果 *shell* 为
True
,则指定的命令将通过 shell 执行。如果您主要使用 Python 是为了利用其优于大多数系统 shell 的增强控制流,并且仍然希望方便地访问其他 shell 功能(例如 shell 管道、文件名通配符、环境变量扩展以及将~
扩展为用户的主目录),那么这将非常有用。但是,请注意,Python 本身提供了许多类似 shell 的功能的实现(特别是glob
、fnmatch
、os.walk()
、os.path.expandvars()
、os.path.expanduser()
和shutil
)。版本 3.3 中的变化: 当 *universal_newlines* 为
True
时,该类使用编码locale.getpreferredencoding(False)
而不是locale.getpreferredencoding()
。有关此更改的更多信息,请参阅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=(), *, group=None, extra_groups=None, user=None, umask=-1, encoding=None, errors=None, text=None, pipesize=-1, process_group=None)¶
在新进程中执行子程序。在 POSIX 上,该类使用类似于
os.execvpe()
的行为来执行子程序。在 Windows 上,该类使用 WindowsCreateProcess()
函数。Popen
的参数如下。args 应该是一个程序参数序列,或者是一个字符串或 类路径对象。默认情况下,如果 *args* 是一个序列,则要执行的程序是 *args* 中的第一个项目。如果 *args* 是一个字符串,则解释取决于平台,如下所述。有关与默认行为的其他差异,请参阅 *shell* 和 *executable* 参数。除非另有说明,否则建议将 *args* 作为序列传递。
警告
为了获得最大的可靠性,请对可执行文件使用完全限定路径。要在
PATH
上搜索非限定名称,请使用shutil.which()
。在所有平台上,传递sys.executable
是再次启动当前 Python 解释器的推荐方法,并使用-m
命令行格式启动已安装的模块。解析 *executable*(或 *args* 的第一项)的路径取决于平台。对于 POSIX,请参阅
os.execvpe()
,并注意在解析或搜索可执行文件路径时,*cwd* 会覆盖当前工作目录,而 *env* 可以覆盖PATH
环境变量。对于 Windows,请参阅 WinAPICreateProcess
的lpApplicationName
和lpCommandLine
参数的文档,并注意在使用shell=False
解析或搜索可执行文件路径时,*cwd* 不会覆盖当前工作目录,而 *env* 也不能覆盖PATH
环境变量。使用完整路径可以避免所有这些差异。以下示例演示了如何将一些参数作为序列传递给外部程序:
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 中的变化: 如果 *shell* 为
False
,则 *args* 参数接受 类路径对象;如果 *shell* 为False
且在 POSIX 上,则 *args* 参数接受包含类路径对象的序列。版本 3.8 中的变化: 如果 *shell* 为
False
,则 *args* 参数接受 类路径对象;如果 *shell* 为False
且在 Windows 上,则 *args* 参数接受包含字节和类路径对象的序列。*shell* 参数(默认为
False
)指定是否使用 shell 作为要执行的程序。如果 *shell* 为True
,建议将 *args* 作为字符串而不是序列传递。在 POSIX 上,如果
shell=True
,则 shell 默认为/bin/sh
。如果 *args* 是字符串,则该字符串指定要通过 shell 执行的命令。这意味着该字符串的格式必须与在 shell 提示符下键入时的格式完全相同。例如,这包括对文件名中的空格使用引号或反斜杠转义。如果 *args* 是一个序列,则第一项指定命令字符串,任何其他项将被视为 shell 本身的附加参数。也就是说,Popen
等效于:Popen(['/bin/sh', '-c', args[0], args[1], ...])
在 Windows 上,如果
shell=True
,则COMSPEC
环境变量指定默认 shell。您只需要在要执行的命令内置于 shell 中时(例如 dir 或 copy)才需要在 Windows 上指定shell=True
。您不需要shell=True
即可运行批处理文件或基于控制台的可执行文件。注意
在使用
shell=True
之前,请阅读 安全注意事项 部分。在创建 stdin/stdout/stderr 管道文件对象时,*bufsize* 将作为相应参数提供给
open()
函数。0
表示无缓冲(读取和写入是一个系统调用,并且可能返回短数据)。1
表示行缓冲(仅在text=True
或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 中的变化: 在 POSIX 上,*executable* 参数接受 类路径对象。
版本 3.8 中的变化: 在 Windows 上,*executable* 参数接受字节和 类路径对象。
3.12 版更改: 更改了 Windows shell 对
shell=True
的搜索顺序。当前目录和%PATH%
被替换为%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,将名为cmd.exe
的恶意程序放入当前目录将不再起作用。*stdin*、*stdout* 和 *stderr* 分别指定已执行程序的标准输入、标准输出和标准错误文件句柄。有效值为
None
、PIPE
、DEVNULL
、现有文件描述符(正整数)和具有有效文件描述符的现有 文件对象。使用None
的默认设置时,不会发生重定向。PIPE
指示应创建到子进程的新管道。DEVNULL
指示将使用特殊文件os.devnull
。此外,*stderr* 可以是STDOUT
,这表示来自应用程序的 stderr 数据应捕获到与 *stdout* 相同的文件句柄中。如果 *preexec_fn* 设置为可调用对象,则将在执行子进程之前立即在子进程中调用此对象。(仅限 POSIX)
警告
如果您的应用程序中存在线程,则使用 *preexec_fn* 参数是不安全的。子进程可能在调用 exec 之前死锁。
注意
如果需要修改子进程的环境,请使用 *env* 参数,而不是在 *preexec_fn* 中进行修改。*start_new_session* 和 *process_group* 参数应取代使用 *preexec_fn* 在子进程中调用
os.setsid()
或os.setpgid()
的代码。版本 3.8 中的变化: 子解释器不再支持 *preexec_fn* 参数。在子解释器中使用该参数会引发
RuntimeError
。新的限制可能会影响部署在 mod_wsgi、uWSGI 和其他嵌入式环境中的应用程序。如果 close_fds 为 true,则在执行子进程之前,除了
0
、1
和2
之外的所有文件描述符都将被关闭。否则,当 close_fds 为 false 时,文件描述符将遵循 文件描述符的继承 中所述的可继承标志。在 Windows 上,如果 close_fds 为 true,则子进程不会继承任何句柄,除非在
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 可以是字符串、字节串或 类路径对象。在 POSIX 上,如果可执行文件路径是相对路径,则该函数会相对于 cwd 查找 executable(或 args 中的第一个项目)。版本 3.6 中的变化: cwd 参数在 POSIX 上接受 类路径对象。
版本 3.7 中的变化: cwd 参数在 Windows 上接受 类路径对象。
版本 3.8 中的变化: cwd 参数在 Windows 上接受字节串对象。
如果 restore_signals 为 true(默认值),则在执行子进程之前,Python 已设置为 SIG_IGN 的所有信号都会在子进程中恢复为 SIG_DFL。当前,这包括 SIGPIPE、SIGXFZ 和 SIGXFSZ 信号。(仅限 POSIX)
版本 3.2 中的变化: 添加了 restore_signals。
如果 start_new_session 为 true,则在执行子进程之前,将在子进程中调用
setsid()
系统调用。可用性:POSIX
版本 3.2 中的变化: 添加了 start_new_session。
如果 process_group 是一个非负整数,则在执行子进程之前,将在子进程中调用
setpgid(0, value)
系统调用。可用性:POSIX
版本 3.11 中的变化: 添加了 process_group。
如果 group 不为
None
,则在执行子进程之前,将在子进程中调用 setregid() 系统调用。如果提供的值是字符串,则将通过grp.getgrnam()
查找该值,并将使用gr_gid
中的值。如果该值是一个整数,则将按原样传递。(仅限 POSIX)可用性:POSIX
版本 3.9 中的新功能。
如果 extra_groups 不为
None
,则在执行子进程之前,将在子进程中调用 setgroups() 系统调用。将在 extra_groups 中提供的字符串通过grp.getgrnam()
查找,并将使用gr_gid
中的值。整数值将按原样传递。(仅限 POSIX)可用性:POSIX
版本 3.9 中的新功能。
如果 user 不为
None
,则在执行子进程之前,将在子进程中调用 setreuid() 系统调用。如果提供的值是字符串,则将通过pwd.getpwnam()
查找该值,并将使用pw_uid
中的值。如果该值是一个整数,则将按原样传递。(仅限 POSIX)可用性:POSIX
版本 3.9 中的新功能。
如果 umask 不为负数,则在执行子进程之前,将在子进程中调用 umask() 系统调用。
可用性:POSIX
版本 3.9 中的新功能。
如果 env 不为
None
,则它必须是一个映射,用于定义新进程的环境变量;这些变量将取代继承当前进程环境的默认行为。此映射可以是在任何平台上从字符串到字符串,或在 POSIX 平台上从字节串到字节串,就像os.environ
或os.environb
一样。注意
如果指定了 env,则它必须提供程序执行所需的任何变量。在 Windows 上,为了运行 并行程序集,指定的 env 必须 包含有效的
SystemRoot
。如果指定了 encoding 或 errors,或者 text 为 true,则文件对象 stdin、stdout 和 stderr 将以文本模式打开,并使用指定的 encoding 和 errors,如上面的 常用参数 中所述。 universal_newlines 参数等效于 text,提供它是为了向后兼容。默认情况下,文件对象以二进制模式打开。
版本 3.6 中的新功能: 添加了 encoding 和 errors。
版本 3.7 中的新功能: 添加了 text 作为 universal_newlines 的更可读别名。
如果给定,startupinfo 将是一个
STARTUPINFO
对象,它将被传递给底层的CreateProcess
函数。如果给定,creationflags 可以是一个或多个以下标志
当对 stdin、stdout 或 stderr 使用
PIPE
时,可以使用 pipesize 来更改管道的大小。管道的大小仅在支持此功能的平台上才会更改(在撰写本文时仅限 Linux)。其他平台将忽略此参数。版本 3.10 中的变化: 添加了 pipesize 参数。
Popen 对象通过
with
语句支持上下文管理器:退出时,标准文件描述符将关闭,并等待进程结束。with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read())
Popen 和此模块中使用它的其他函数会引发 审计事件
subprocess.Popen
,其参数为executable
、args
、cwd
和env
。args
的值可以是单个字符串或字符串列表,具体取决于平台。版本 3.2 中的变化: 添加了上下文管理器支持。
3.6 版更改: 如果子进程仍在运行,
Popen
析构函数现在会发出ResourceWarning
警告。3.8 版更改:
Popen
可以在某些情况下使用os.posix_spawn()
以获得更好的性能。在适用于 Linux 的 Windows 子系统和 QEMU 用户仿真中,使用os.posix_spawn()
的Popen
构造函数不再在程序丢失等错误时引发异常,但子进程会因非零returncode
而失败。
异常¶
在新程序开始执行之前,子进程中引发的异常将在父进程中重新引发。
引发的最常见异常是 OSError
。例如,当尝试执行不存在的文件时,就会发生这种情况。应用程序应该为 OSError
异常做好准备。请注意,当 shell=True
时,仅当未找到所选 shell 本身时,子进程才会引发 OSError
。要确定 shell 是否未能找到请求的应用程序,需要检查子进程的返回代码或输出。
如果使用无效参数调用 Popen
,则会引发 ValueError
。
如果被调用进程返回非零返回代码,check_call()
和 check_output()
将引发 CalledProcessError
。
接受 *timeout* 参数的所有函数和方法(例如 run()
和 Popen.communicate()
)如果在进程退出之前超时,将引发 TimeoutExpired
。
此模块中定义的异常都继承自 SubprocessError
。
3.3 版新增: 添加了 SubprocessError
基类。
安全注意事项¶
与其他一些 popen 函数不同,此库不会隐式选择调用系统 shell。这意味着所有字符(包括 shell 元字符)都可以安全地传递给子进程。如果通过 shell=True
显式调用 shell,则应用程序有责任确保所有空格和元字符都已正确引用,以避免 shell 注入 漏洞。在 某些平台 上,可以使用 shlex.quote()
进行此转义。
在 Windows 上,操作系统可能会在系统 shell 中启动批处理文件(*.bat
或 *.cmd
),而不管传递给此库的参数是什么。这可能会导致根据 shell 规则解析参数,但 Python 不会添加任何转义。如果您打算使用来自不受信任来源的参数启动批处理文件,请考虑传递 shell=True
以允许 Python 转义特殊字符。有关其他讨论,请参阅 gh-114539。
Popen 对象¶
Popen
类的实例具有以下方法
- Popen.poll()¶
检查子进程是否已终止。设置并返回
returncode
属性。否则,返回None
。
- Popen.wait(timeout=None)¶
等待子进程终止。设置并返回
returncode
属性。如果进程在 *timeout* 秒后未终止,则引发
TimeoutExpired
异常。可以安全地捕获此异常并重试等待。注意
当使用
stdout=PIPE
或stderr=PIPE
并且子进程生成到管道的数据量足以使其阻塞等待操作系统管道缓冲区接受更多数据时,这将导致死锁。使用管道时,请使用Popen.communicate()
以避免这种情况。注意
当 *timeout* 参数不是
None
时,(在 POSIX 上)该函数使用忙循环(非阻塞调用和短睡眠)实现。对异步等待使用asyncio
模块:请参阅asyncio.create_subprocess_exec
。3.3 版更改: 添加了 *timeout*。
- Popen.communicate(input=None, timeout=None)¶
与进程交互:将数据发送到 stdin。从 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 可以发送到使用包含CREATE_NEW_PROCESS_GROUP
的 *creationflags* 参数启动的进程。
- Popen.terminate()¶
停止子进程。在 POSIX 操作系统上,该方法向子进程发送
SIGTERM
。在 Windows 上,调用 Win32 API 函数TerminateProcess()
来停止子进程。
- Popen.kill()¶
杀死子进程。在 POSIX 操作系统上,该函数向子进程发送 SIGKILL。在 Windows 上,
kill()
是terminate()
的别名。
以下属性也由类设置,供您访问。不支持将它们重新分配给新值。
- Popen.stdin¶
如果 *stdin* 参数是
PIPE
,则此属性是由open()
返回的可写流对象。如果指定了 *encoding* 或 *errors* 参数,或者 *text* 或 *universal_newlines* 参数为True
,则该流是文本流,否则它是字节流。如果 *stdin* 参数不是PIPE
,则此属性为None
。
- Popen.stdout¶
如果 *stdout* 参数是
PIPE
,则此属性是由open()
返回的可读流对象。从流中读取提供来自子进程的输出。如果指定了 *encoding* 或 *errors* 参数,或者 *text* 或 *universal_newlines* 参数为True
,则该流是文本流,否则它是字节流。如果 *stdout* 参数不是PIPE
,则此属性为None
。
- Popen.stderr¶
如果 *stderr* 参数是
PIPE
,则此属性是由open()
返回的可读流对象。从流中读取提供来自子进程的错误输出。如果指定了 *encoding* 或 *errors* 参数,或者 *text* 或 *universal_newlines* 参数为True
,则该流是文本流,否则它是字节流。如果 *stderr* 参数不是PIPE
,则此属性为None
。
警告
使用 communicate()
而不是 .stdin.write
、.stdout.read
或 .stderr.read
,以避免由于任何其他操作系统管道缓冲区填满并阻塞子进程而导致的死锁。
- Popen.pid¶
子进程的进程 ID。
请注意,如果将 *shell* 参数设置为
True
,则这是生成的 shell 的进程 ID。
- Popen.returncode¶
子进程返回代码。最初为
None
,如果poll()
、wait()
或communicate()
方法检测到进程已终止,则会设置returncode
。None
值表示在上次方法调用时进程尚未终止。负值
-N
表示子进程被信号N
终止(仅限 POSIX)。
Windows Popen 帮助程序¶
STARTUPINFO
类和以下常量仅在 Windows 上可用。
- class subprocess.STARTUPINFO(*, dwFlags=0, hStdInput=None, hStdOutput=None, hStdError=None, wShowWindow=0, lpAttributeList=None)¶
用于
Popen
创建的部分支持 Windows STARTUPINFO 结构。可以通过将以下属性作为仅关键字参数传递来设置它们。版本 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
除外。否则,将忽略此属性。
- lpAttributeList¶
一个字典,包含
STARTUPINFOEX
中给出的用于创建进程的其他属性,请参阅 UpdateProcThreadAttribute。支持的属性
- handle_list
将被继承的句柄序列。如果非空,则 close_fds 必须为 true。
当传递给
Popen
构造函数时,句柄必须通过os.set_handle_inheritable()
临时设置为可继承,否则将引发带有 Windows 错误代码ERROR_INVALID_PARAMETER
(87) 的OSError
。警告
在多线程进程中,将此功能与对继承所有句柄的其他进程创建函数(例如
os.system()
)的并发调用结合使用时,请谨慎操作,以避免泄漏标记为可继承的句柄。这也适用于标准句柄重定向,它会临时创建可继承的句柄。
3.7 版新增。
Windows 常量¶
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.REALTIME_PRIORITY_CLASS¶
一个
Popen
creationflags
参数,用于指定新进程将具有实时优先级。您几乎永远不应该使用 REALTIME_PRIORITY_CLASS,因为它会中断管理鼠标输入、键盘输入和后台磁盘刷新的系统线程。此类适用于“直接”与硬件通信或执行应限制中断的简短任务的应用程序。3.7 版新增。
- subprocess.DETACHED_PROCESS¶
一个
Popen
creationflags
参数,用于指定新进程不会继承其父级的控制台。此值不能与 CREATE_NEW_CONSOLE 一起使用。3.7 版新增。
旧版高级 API¶
在 Python 3.5 之前,这三个函数构成了 subprocess 的高级 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*。
3.12 版更改: 更改了 Windows shell 对
shell=True
的搜索顺序。当前目录和%PATH%
被替换为%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,将名为cmd.exe
的恶意程序放入当前目录将不再起作用。
- subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs)¶
使用参数运行命令。等待命令完成。如果返回码为零则返回,否则引发
CalledProcessError
。CalledProcessError
对象将在returncode
属性中包含返回码。如果check_call()
无法启动进程,它将传播引发的异常。需要捕获 stdout 或 stderr 的代码应该改用
run()
run(..., check=True)
要抑制 stdout 或 stderr,请提供
DEVNULL
的值。上面显示的参数只是一些常见的参数。完整的函数签名与
Popen
构造函数的签名相同 - 此函数将除 timeout 之外的所有提供的参数直接传递给该接口。注意
不要将
stdout=PIPE
或stderr=PIPE
与此函数一起使用。如果子进程生成足够的输出到管道以填满操作系统管道缓冲区,则子进程将阻塞,因为没有从管道中读取数据。3.3 版更改: 添加了 *timeout*。
3.12 版更改: 更改了 Windows shell 对
shell=True
的搜索顺序。当前目录和%PATH%
被替换为%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,将名为cmd.exe
的恶意程序放入当前目录将不再起作用。
- 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
来覆盖此行为,如 常用参数 和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 的更可读别名。
3.12 版更改: 更改了 Windows shell 对
shell=True
的搜索顺序。当前目录和%PATH%
被替换为%COMSPEC%
和%SystemRoot%\System32\cmd.exe
。因此,将名为cmd.exe
的恶意程序放入当前目录将不再起作用。
使用 subprocess
模块替换旧函数¶
在本节中,“a 变为 b”表示 b 可以用作 a 的替代品。
注意
如果找不到可执行程序,则本节中的所有“a”函数都会(或多或少)静默地失败;“b”替代品会引发 OSError
。
此外,如果请求的操作产生非零返回码,则使用 check_output()
的替代品将失败,并显示 CalledProcessError
。输出仍然可用作引发异常的 output
属性。
在以下示例中,我们假设已从 subprocess
模块中导入了相关函数。
替换 /bin/sh shell 命令替换¶
output=$(mycmd myarg)
变为
output = check_output(["mycmd", "myarg"])
替换 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()
调用非常重要,以便在 p1 之前退出 p2 时,p1 能够接收到 SIGPIPE。
或者,对于受信任的输入,仍然可以直接使用 shell 自身的管道支持
output=$(dmesg | grep hda)
变为
output = check_output("dmesg | grep hda", shell=True)
替换 os.system()
¶
sts = os.system("mycmd" + " myarg")
# becomes
retcode = call("mycmd" + " myarg", shell=True)
备注
通常不需要通过 shell 调用程序。
call()
返回值的编码方式与os.system()
不同。os.system()
函数在命令运行时会忽略 SIGINT 和 SIGQUIT 信号,但在使用subprocess
模块时,调用者必须单独执行此操作。
更现实的例子如下所示
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
基本相同,不同之处在于
旧版 Shell 调用函数¶
此模块还提供来自 2.x 版 commands
模块的以下旧函数。这些操作会隐式调用系统 shell,并且上述关于安全性和异常处理一致性的保证对这些函数无效。
- subprocess.getstatusoutput(cmd, *, encoding=None, errors=None)¶
返回在 shell 中执行 cmd 的
(exitcode, output)
。使用
Popen.check_output()
在 shell 中执行字符串 cmd 并返回一个 2 元组(exitcode, output)
。encoding 和 errors 用于解码输出;有关更多详细信息,请参阅常用参数的注释。输出中会删除尾随换行符。命令的退出代码可以解释为 subprocess 的返回代码。示例
>>> 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, '')
可用性:Unix、Windows。
在 3.3.4 版更改: 添加了 Windows 支持。
该函数现在返回 (exitcode, output),而不是 Python 3.3.3 及更早版本中的 (status, output)。exitcode 的值与
returncode
相同。在 3.11 版更改: 添加了 encoding 和 errors 参数。
- subprocess.getoutput(cmd, *, encoding=None, errors=None)¶
返回在 shell 中执行 cmd 的输出(stdout 和 stderr)。
与
getstatusoutput()
类似,只是忽略退出代码,返回值是一个包含命令输出的字符串。示例>>> subprocess.getoutput('ls /bin/ls') '/bin/ls'
可用性:Unix、Windows。
在 3.3.4 版更改: 添加了 Windows 支持
在 3.11 版更改: 添加了 encoding 和 errors 参数。
备注¶
在 Windows 上将参数序列转换为字符串¶
在 Windows 上,args 序列会被转换为可以使用以下规则解析的字符串(这些规则与 MS C 运行时使用的规则相对应)
参数由空格分隔,空格可以是空格或制表符。
用双引号括起来的字符串被解释为单个参数,无论其中包含什么空格。带引号的字符串可以嵌入到参数中。
前面有反斜杠的双引号被解释为文字双引号。
反斜杠按字面解释,除非它们紧跟在双引号前面。
如果反斜杠紧跟在双引号前面,则每对反斜杠都被解释为文字反斜杠。如果反斜杠的数量为奇数,则最后一个反斜杠会像规则 3 中所述那样转义下一个双引号。
另请参阅
shlex
提供用于解析和转义命令行的函数的模块。
禁用 vfork()
或 posix_spawn()
的使用¶
在 Linux 上,subprocess
默认在安全的情况下在内部使用 vfork()
系统调用,而不是 fork()
。这大大提高了性能。
如果您遇到需要阻止 Python 使用 vfork()
的非常不寻常的情况,可以将 subprocess._USE_VFORK
属性设置为假值。
subprocess._USE_VFORK = False # See CPython issue gh-NNNNNN.
此设置对 posix_spawn()
的使用没有影响,后者可以在其 libc 实现中内部使用 vfork()
。如果您需要阻止使用该函数,则可以使用类似的 subprocess._USE_POSIX_SPAWN
属性。
subprocess._USE_POSIX_SPAWN = False # See CPython issue gh-NNNNNN.
在任何 Python 版本上都可以安全地将它们设置为 false。当不受支持时,它们对旧版本没有影响。不要假设这些属性可用于读取。尽管有它们的名称,但真值并不表示将使用相应的函数,而只是表示可以使用。
每当您必须使用这些私有旋钮时,请提交问题,并提供重现您所看到问题的方法。在代码注释中链接到该问题。
3.8 版的新增功能: _USE_POSIX_SPAWN
3.11 版的新增功能: _USE_VFORK