subprocess — 子进程管理

源代码: Lib/subprocess.py


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

os.system
os.spawn*

有关如何使用 subprocess 模块替换这些模块和函数的信息可以在以下部分找到。

参见

PEP 324 – 提出 subprocess 模块的 PEP

可用性:不是 Android,不是 iOS,不是 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 构造函数基本相同 - 此函数的大部分参数都会传递到该接口。(timeoutinputcheckcapture_output 不是。)

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

可以在秒内指定 timeout,它会在内部传递给 Popen.communicate()。如果超时到期,子进程将被杀死并等待。在子进程终止后,将重新引发 TimeoutExpired 异常。在许多平台 API 上,初始进程创建本身无法中断,因此在进程创建需要多长时间之后,你至少才能看到超时异常。

input 参数会传递给 Popen.communicate(),进而传递给子进程的标准输入 (stdin)。如果使用该参数,则必须是字节序列,或者如果指定了 encodingerrors,或者 text 为 true,则必须是字符串。当使用此参数时,内部的 Popen 对象会自动创建,并将 stdin 设置为 PIPE,并且不能同时使用 stdin 参数。

如果 check 为 true,并且进程以非零退出代码退出,则会引发 CalledProcessError 异常。该异常的属性会保存参数、退出代码以及捕获的 stdout 和 stderr。

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

如果 env 不是 None,则它必须是一个映射,定义新进程的环境变量;这些环境变量将代替继承当前进程环境的默认行为。它直接传递给 Popen。此映射可以是任何平台上的 str 到 str,或者像 os.environos.environb 一样,是 POSIX 平台上的 bytes 到 bytes。

示例

>>> 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 版本中变更: 添加了 encodingerrors 参数

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

在 3.12 版本中变更: 更改了 shell=True 的 Windows shell 搜索顺序。当前目录和 %PATH% 被替换为 %COMSPEC%%SystemRoot%\System32\cmd.exe。因此,将名为 cmd.exe 的恶意程序放入当前目录不再有效。

class subprocess.CompletedProcess

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

args

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

returncode

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

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

stdout

从子进程捕获的 stdout。 字节序列,或者如果调用 run() 时使用了 encoding、errors 或 text=True,则为字符串。 如果未捕获 stdout,则为 None

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

stderr

从子进程捕获的 stderr。 字节序列,或者如果调用 run() 时使用了 encoding、errors 或 text=True,则为字符串。 如果未捕获 stderr,则为 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 的子类,当等待子进程时超时过期时引发。

cmd

用于生成子进程的命令。

timeout

以秒为单位的超时时间。

output

如果子进程被 run()check_output() 捕获,则为子进程的输出。 否则,为 None。 当捕获到任何输出时,这始终是 bytes,无论 text=True 设置如何。当没有观察到输出时,它可能会保持为 None 而不是 b''

stdout

与 output 的别名,与 stderr 对称。

stderr

如果子进程被 run() 捕获,则为子进程的 stderr 输出。 否则,为 None。 当捕获到 stderr 输出时,这始终是 bytes,无论 text=True 设置如何。当没有观察到 stderr 输出时,它可能会保持为 None 而不是 b''

3.3 版本新增。

在 3.5 版本中变更: 添加了 stdoutstderr 属性

exception subprocess.CalledProcessError

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

returncode

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

cmd

用于生成子进程的命令。

output

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

stdout

stderr 对称的输出别名。

stderr

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

在 3.5 版本中变更: 添加了 stdoutstderr 属性

常用参数

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

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

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

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

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

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

在 3.6 版本中更改: 添加了 *encoding* 和 *errors* 参数。

在 3.7 版本中更改: 添加了 *text* 参数作为 *universal_newlines* 的别名。

注意

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

如果 *shell* 为 True,则指定的命令将通过 shell 执行。如果您主要使用 Python 来增强对大多数系统 shell 的控制流,并且仍然希望方便地访问其他 shell 功能(例如 shell 管道、文件名通配符、环境变量扩展以及将 ~ 扩展为用户的 home 目录),这可能很有用。但是,请注意,Python 本身提供了许多类似 shell 的功能的实现(特别是 globfnmatchos.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 系统上,该类使用 Windows 的 CreateProcess() 函数。Popen 的参数如下。

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

警告

为了获得最大的可靠性,请为可执行文件使用完全限定的路径。要在 PATH 上搜索非限定名称,请使用 shutil.which()。在所有平台上,传递 sys.executable 是再次启动当前 Python 解释器的推荐方法,并使用 -m 命令行格式启动已安装的模块。

解析 executable(或 args 的第一项)的路径取决于平台。对于 POSIX 系统,请参阅 os.execvpe(),并注意在解析或搜索可执行文件路径时,cwd 会覆盖当前工作目录,而 env 可以覆盖 PATH 环境变量。对于 Windows 系统,请参阅 WinAPI CreateProcesslpApplicationNamelpCommandLine 参数的文档,并注意当使用 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 版本中更改: 如果 shellFalse,则 args 参数接受路径类对象,在 POSIX 系统上接受包含路径类对象的序列。

在 3.8 版本中更改: 如果 shellFalse,则 args 参数接受路径类对象,在 Windows 系统上接受包含字节和路径类对象的序列。

shell 参数(默认为 False)指定是否将 shell 用作要执行的程序。如果 shellTrue,建议将 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 中时(例如 dircopy)。您不需要 shell=True 来运行批处理文件或基于控制台的可执行文件。

注意

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

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

  • 0 表示无缓冲(读取和写入是一个系统调用,并且可以返回较短的内容)

  • 1 表示行缓冲(仅当 text=Trueuniversal_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 系统上接受字节串和路径类对象

在 3.12 版本中变更: 更改了 shell=True 的 Windows shell 搜索顺序。当前目录和 %PATH% 被替换为 %COMSPEC%%SystemRoot%\System32\cmd.exe。因此,将名为 cmd.exe 的恶意程序放入当前目录不再有效。

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

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

警告

在应用程序中存在线程的情况下,使用 preexec_fn 参数是不安全的。子进程可能会在调用 exec 之前发生死锁。

注意

如果需要修改子进程的环境,请使用 env 参数,而不是在 preexec_fn 中执行此操作。start_new_sessionprocess_group 参数应取代使用 preexec_fn 调用 os.setsid()os.setpgid() 在子进程中的代码。

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

如果 close_fds 为 true,则除了 012 之外的所有文件描述符都将在子进程执行之前关闭。否则,当 close_fds 为 false 时,文件描述符将按照 文件描述符的继承 中的描述遵守其可继承标志。

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

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

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

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

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

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

在 3.6 版本中更改: cwd 参数在 POSIX 系统上接受路径类对象

在 3.7 版本中更改: cwd 参数在 Windows 系统上接受路径类对象

在 3.8 版本中更改: cwd 参数在 Windows 系统上接受字节串对象。

如果 restore_signals 为 true(默认值),则 Python 已设置为 SIG_IGN 的所有信号将在 exec 之前在子进程中恢复为 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.environos.environb 非常相似。

注意

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

如果指定了 encodingerrors,或者 text 为 true,则文件对象 stdinstdoutstderr 将以文本模式打开,并使用指定的 encodingerrors,如上文常用参数中所述。universal_newlines 参数等效于 text,并且是为了向后兼容而提供的。默认情况下,文件对象以二进制模式打开。

3.6 版本新增: 添加了 encodingerrors 参数。

3.7 版本新增: 添加了 text 参数,作为 universal_newlines 更易读的别名。

如果给定 startupinfo,它将是一个 STARTUPINFO 对象,该对象将传递给底层的 CreateProcess 函数。

如果给定 creationflags,则可以是一个或多个以下标志:

stdin, stdoutstderr 使用 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, cwdenvargs 的值可能是一个单独的字符串或一个字符串列表,具体取决于平台。

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

3.6 版本更改: 如果子进程仍在运行,Popen 析构函数现在会发出一个 ResourceWarning 警告。

3.8 版本更改: 在某些情况下,Popen 可以使用 os.posix_spawn() 以获得更好的性能。在 Windows Linux 子系统和 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 上,批处理文件(*.bat*.cmd)可能会被操作系统在系统 shell 中启动,而不管传递给此库的参数如何。这可能会导致参数根据 shell 规则进行解析,而 Python 不会添加任何转义。如果您有意使用来自不可信来源的参数启动批处理文件,请考虑传递 shell=True 以允许 Python 转义特殊字符。有关其他讨论,请参阅 gh-114539

Popen 对象

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

Popen.poll()

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

Popen.wait(timeout=None)

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

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

注意

当使用 stdout=PIPEstderr=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 发送数据,则需要使用 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_GROUPcreationflags 参数启动的进程。

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() 返回的可写流对象。如果指定了 encodingerrors 参数,或者 textuniversal_newlines 参数是 True,则该流是文本流,否则是字节流。如果 stdin 参数不是 PIPE,则此属性为 None

Popen.stdout

如果 stdout 参数是 PIPE,则此属性是由 open() 返回的可读流对象。从流读取可以提供来自子进程的输出。如果指定了 encodingerrors 参数,或者 textuniversal_newlines 参数是 True,则该流是文本流,否则是字节流。如果 stdout 参数不是 PIPE,则此属性为 None

Popen.stderr

如果 stderr 参数是 PIPE,则此属性是由 open() 返回的可读流对象。从流读取可以提供来自子进程的错误输出。如果指定了 encodingerrors 参数,或者 textuniversal_newlines 参数是 True,则该流是文本流,否则是字节流。如果 stderr 参数不是 PIPE,则此属性为 None

警告

请使用 communicate() 而不是 .stdin.write.stdout.read.stderr.read,以避免由于任何其他操作系统管道缓冲区已满而导致子进程阻塞的死锁。

Popen.pid

子进程的进程 ID。

请注意,如果将 shell 参数设置为 True,则这是生成的外壳的进程 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)

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 为此属性提供。 当 Popen 使用 shell=True 调用时会用到它。

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.hStdInputSTARTUPINFO.hStdOutputSTARTUPINFO.hStdError 属性包含附加信息。

subprocess.STARTF_USESHOWWINDOW

指定 STARTUPINFO.wShowWindow 属性包含附加信息。

subprocess.STARTF_FORCEONFEEDBACK

用于指定在进程启动时显示 *正在后台工作* 鼠标光标的 STARTUPINFO.dwFlags 参数。 这是 GUI 进程的默认行为。

在 3.13 版本中添加。

subprocess.STARTF_FORCEOFFFEEDBACK

用于指定在启动进程时不更改鼠标光标的 STARTUPINFO.dwFlags 参数。

在 3.13 版本中添加。

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 之前,这三个函数组成了 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=PIPEstderr=PIPE 与此函数一起使用。如果子进程生成足够多的输出到管道以填满操作系统管道缓冲区,则子进程将会阻塞,因为没有从管道读取数据。

3.3 版本更改: 添加了 timeout 参数。

在 3.12 版本中变更: 更改了 shell=True 的 Windows shell 搜索顺序。当前目录和 %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)

运行带有参数的命令。等待命令完成。如果返回代码为零,则返回,否则引发 CalledProcessErrorCalledProcessError 对象将在 returncode 属性中包含返回代码。如果 check_call() 无法启动进程,它将传播引发的异常。

需要捕获 stdout 或 stderr 的代码应改用 run()

run(..., check=True)

要禁止 stdout 或 stderr,请提供 DEVNULL 的值。

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

注意

不要将 stdout=PIPEstderr=PIPE 与此函数一起使用。如果子进程生成足够多的输出到管道以填满操作系统管道缓冲区,则子进程将会阻塞,因为没有从管道读取数据。

3.3 版本更改: 添加了 timeout 参数。

在 3.12 版本中变更: 更改了 shell=True 的 Windows shell 搜索顺序。当前目录和 %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)

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

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

这等效于

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

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

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

可以通过将 textencodingerrorsuniversal_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 版本中更改: 添加了 encodingerrors。有关详细信息,请参阅 run()

3.7 版本新增: 添加了 text 参数,作为 universal_newlines 更易读的别名。

在 3.12 版本中变更: 更改了 shell=True 的 Windows shell 搜索顺序。当前目录和 %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() 非常重要,这样如果 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
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"])

Vector 示例

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

Environment 示例

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.Popen3popen2.Popen4 的基本工作方式与 subprocess.Popen 相同,只是

  • 如果执行失败,Popen 会抛出异常。

  • capturestderr 参数被 stderr 参数替换。

  • 必须指定 stdin=PIPEstdout=PIPE

  • popen2 默认关闭所有文件描述符,但是您必须使用 Popen 指定 close_fds=True,以保证在所有平台或过去的 Python 版本上的这种行为。

旧版 Shell 调用函数

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

subprocess.getstatusoutput(cmd, *, encoding=None, errors=None)

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

使用 Popen.check_output() 在 shell 中执行字符串 cmd 并返回一个 2 元组 (exitcode, output)encodingerrors 用于解码输出;有关更多详细信息,请参阅关于 常用参数 的说明。

输出中的尾部换行符会被删除。命令的退出代码可以解释为子进程的返回代码。示例

>>> 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 版本中更改: 添加了 encodingerrors 参数。

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 版本中更改: 添加了 encodingerrors 参数。

说明

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

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

  1. 参数由空格分隔,空格可以是空格或制表符。

  2. 用双引号括起来的字符串被解释为单个参数,而不管其中包含的空格如何。带引号的字符串可以嵌入到参数中。

  3. 前面有反斜杠的双引号被解释为字面双引号。

  4. 反斜杠按字面解释,除非它们紧邻双引号之前。

  5. 如果反斜杠紧邻双引号之前,则每对反斜杠被解释为字面反斜杠。如果反斜杠的数量是奇数,则最后一个反斜杠将转义下一个双引号,如规则 3 中所述。

参见

shlex

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

禁用 vfork()posix_spawn() 的使用

在 Linux 上,subprocess 默认情况下,在安全的情况下内部使用 vfork() 系统调用,而不是 fork()。这大大提高了性能。

如果您遇到需要阻止 Python 使用 vfork() 的极其不寻常的情况,可以将 subprocess._USE_VFORK 属性设置为 false 值。

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 都是安全的。当不支持时,它们对较旧的版本没有影响。不要假设可以读取这些属性。尽管它们有名称,但 true 值并不表示将使用相应的函数,而只是可能使用。

如果您必须使用这些私有旋钮,请随时提交问题,并提供重现您遇到的问题的方法。请在代码的注释中链接到该问题。

在 3.8 版本中添加: _USE_POSIX_SPAWN

在 3.11 版本中添加: _USE_VFORK