17.1. subprocess — 子流程管理 — Python 文档

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

17.1. 子流程 — 子流程管理

2.4 版中的新功能。


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

os.system
os.spawn*
os.popen*
popen2.*
commands.*

有关如何使用此模块替换旧函数的信息,请参见 subprocess-replacements 部分。

也可以看看

强烈建议 POSIX 用户(Linux、BSD 等)安装和使用更新的 subprocess32 模块,而不是 Python 2.7 附带的版本。 在许多情况下,它是一种更好的行为的替代品。

PEP 324 – PEP 提出子流程模块


17.1.1. 使用子流程模块

启动子流程的推荐方法是使用以下便利功能。 对于无法满足您需求的更高级用例,请使用底层 Popen 接口。

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

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

上面显示的参数只是最常见的参数,在下面的 常用参数 中进行了描述(因此缩写签名中的符号有点奇怪)。 完整的函数签名与 Popen 构造函数的签名相同 - 此函数将所有提供的参数直接传递给该接口。

例子:

>>> subprocess.call(["ls", "-l"])
0

>>> subprocess.call("exit 1", shell=True)
1

警告

使用 shell=True 可能存在安全隐患。 有关详细信息,请参阅 常用参数 下的警告。

笔记

请勿将 stdout=PIPEstderr=PIPE 与此功能一起使用,因为这可能会根据子进程输出量产生死锁。 当您需要管道时,将 Popencommunicate() 方法结合使用。

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

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

上面显示的参数只是最常见的参数,在下面的 常用参数 中进行了描述(因此缩写签名中的符号有点奇怪)。 完整的函数签名与 Popen 构造函数的签名相同 - 此函数将所有提供的参数直接传递给该接口。

例子:

>>> subprocess.check_call(["ls", "-l"])
0

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

2.5 版中的新功能。

警告

使用 shell=True 可能存在安全隐患。 有关详细信息,请参阅 常用参数 下的警告。

笔记

请勿将 stdout=PIPEstderr=PIPE 与此功能一起使用,因为这可能会根据子进程输出量产生死锁。 当您需要管道时,将 Popencommunicate() 方法结合使用。

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

运行带参数的命令并将其输出作为字节字符串返回。

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

上面显示的参数只是最常见的参数,在下面的 常用参数 中进行了描述(因此缩写签名中的符号有点奇怪)。 完整的函数签名与 Popen 构造函数的签名基本相同,除了 stdout 是不允许的,因为它在内部使用。 所有其他提供的参数都直接传递给 Popen 构造函数。

例子:

>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'

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

要同时捕获结果中的标准错误,请使用 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'

2.7 版中的新功能。

警告

使用 shell=True 可能存在安全隐患。 有关详细信息,请参阅 常用参数 下的警告。

笔记

请勿将 stderr=PIPE 与此功能一起使用,因为这可能会根据子进程错误量产生死锁。 当您需要 stderr 管道时,将 Popencommunicate() 方法结合使用。

subprocess.PIPE
可用作 Popenstdinstdoutstderr 参数的特殊值,并指示标准流的管道应该被打开。
subprocess.STDOUT
可用作 Popenstderr 参数的特殊值,并指示标准错误应进入与标准输出相同的句柄。
exception subprocess.CalledProcessError

当由 check_call()check_output() 运行的进程返回非零退出状态时引发异常。

returncode

子进程的退出状态。

cmd

用于生成子进程的命令。

output

如果此异常由 check_output() 引发,则子进程的输出。 否则,None

17.1.1.1. 常用参数

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

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

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

stdoutstderr 是管道并且 universal_newlinesTrue 时,所有行结尾都将被转换为 '\n',如下所述 通用换行符 'U' 模式参数 open()

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

警告

执行包含来自不受信任来源的未经处理的输入的 shell 命令会使程序容易受到 shell 注入 ,这是一个严重的安全漏洞,可能导致任意命令执行。 出于这个原因,在命令字符串是从外部输入构造的情况下,shell=True 的使用 强烈建议

>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / #
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

shell=False 禁用所有基于 shell 的功能,但不受此漏洞影响; 请参阅 Popen 构造函数文档中的注释以获取有关使 shell=False 工作的有用提示。

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


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


17.1.1.2. Popen 构造函数

该模块中的底层进程创建和管理由 Popen 类处理。 它提供了很大的灵活性,因此开发人员能够处理便利功能未涵盖的不太常见的情况。

class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

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

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

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

笔记

shlex.split() 在确定 args 的正确标记化时非常有用,尤其是在复杂情况下:

>>> import shlex, subprocess
>>> command_line = raw_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 作为字符串而不是序列传递。

在带有 shell=True 的 Unix 上,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 可能会带来安全隐患。 有关详细信息,请参阅 常用参数 下的警告。

bufsize,如果给定,则与内置 open() 函数的相应参数含义相同:0 表示无缓冲,1 表示行缓冲,任何其他正值意味着使用(大约)该大小的缓冲区。 负值 bufsize 表示使用系统默认值,通常表示完全缓冲。 bufsize 的默认值为 0(无缓冲)。

笔记

如果您遇到性能问题,建议您尝试通过将 bufsize 设置为 -1 或足够大的正值(例如 4096)来启用缓冲。

executable 参数指定要执行的替换程序。 很少需要它。 当 shell=False 时,executable 替换由 args 指定的要执行的程序。 但是,原始的 args 仍然传递给程序。 大多数程序将 args 指定的程序视为命令名称,然后可以与实际执行的程序不同。 在 Unix 上,args 名称成为实用程序中可执行文件的显示名称,例如 ps。 如果 shell=True,在 Unix 上,executable 参数指定默认 /bin/sh 的替换 shell。

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

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

如果 close_fds 为真,除 012 之外的所有文件描述符都将在子进程执行前关闭。 (仅限 Unix)。 或者,在 Windows 上,如果 close_fds 为真,则子进程将不会继承任何句柄。 请注意,在 Windows 上,您不能将 close_fds 设置为 true,也不能通过设置 stdinstdoutstderr 来重定向标准句柄。

如果 cwd 不是 None,则在执行之前,子节点的当前目录将更改为 cwd。 请注意,搜索可执行文件时不考虑此目录,因此您不能指定程序相对于 cwd 的路径。

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

笔记

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

如果 universal_newlinesTrue,文件对象 stdoutstderruniversal newlines 模式作为文本文件打开。 行可以由 '\n'、Unix 行尾约定、'\r'、旧的 Macintosh 约定或 '\r\n'、Windows 约定中的任何一个终止。 所有这些外部表示都被 Python 程序视为 '\n'

笔记

此功能仅在 Python 使用通用换行支持(默认)构建时可用。 此外,文件对象 stdoutstdinstderr 的换行符属性不会被communication() 方法更新。

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


17.1.1.3. 例外

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

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

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

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


17.1.1.4. 安全

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


17.1.2. 弹出对象

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

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

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

警告

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

Popen.communicate(input=None)

与进程交互:将数据发送到标准输入。 从 stdout 和 stderr 读取数据,直到到达文件结尾。 等待进程终止。 可选的 input 参数应该是要发送到子进程的字符串,或者 None,如果没有数据应该发送到子进程。

communicate() 返回一个元组 (stdoutdata, stderrdata)

请注意,如果要将数据发送到进程的标准输入,则需要使用 stdin=PIPE 创建 Popen 对象。 类似地,要在结果元组中获得除 None 之外的任何内容,您也需要给出 stdout=PIPE 和/或 stderr=PIPE

笔记

读取的数据是缓存在内存中的,所以如果数据量很大或者没有限制就不要使用这种方式。

Popen.send_signal(signal)

发送信号signal给孩子。

笔记

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

2.6 版中的新功能。

Popen.terminate()

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

2.6 版中的新功能。

Popen.kill()

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

2.6 版中的新功能。

还可以使用以下属性:

警告

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


Popen.stdin
如果 stdin 参数是 PIPE,则此属性是一个文件对象,为子进程提供输入。 否则为 None
Popen.stdout
如果 stdout 参数是 PIPE,则此属性是提供子进程输出的文件对象。 否则为 None
Popen.stderr
如果 stderr 参数是 PIPE,则此属性是一个文件对象,它提供来自子进程的错误输出。 否则为 None
Popen.pid

子进程的进程 ID。

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

Popen.returncode

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

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


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

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

17.1.3.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

新进程有一个新的控制台,而不是继承其父级的控制台(默认)。

当使用 shell=True 创建 Popen 时,始终设置此标志。

subprocess.CREATE_NEW_PROCESS_GROUP

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

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


17.1.4. 用子流程模块

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

笔记

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

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


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

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

output=`mycmd myarg`

变成:

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

17.1.4.2. 更换外壳管道

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 在 p1 之前退出时接收 SIGPIPE 很重要。

或者,对于可信输入,仍然可以直接使用 shell 自己的管道支持:

output=`dmesg | grep hda`

变成:

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

17.1.4.3. 更换操作系统()

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

笔记:

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

一个更现实的例子看起来像这样:

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

17.1.4.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.1.4.5. 更换 os.popen() , os.popen2() , os.popen3()

pipe = os.popen("cmd", 'r', bufsize)
==>
pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout
pipe = os.popen("cmd", 'w', bufsize)
==>
pipe = Popen("cmd", shell=True, bufsize=bufsize, stdin=PIPE).stdin
(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)

在 Unix 上,os.popen2、os.popen3 和 os.popen4 也接受一个序列作为要执行的命令,在这种情况下,参数将直接传递给程序而无需 shell 干预。 这种用法可以替换如下:

(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode,
                                        bufsize)
==>
p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (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", shell=True, stdin=PIPE)
...
process.stdin.close()
if process.wait() != 0:
    print "There were some errors"

17.1.4.6. 替换函数 popen2 模块

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

在 Unix 上, popen2 也接受一个序列作为要执行的命令,在这种情况下,参数将直接传递给程序而无需 shell 干预。 这种用法可以替换如下:

(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 默认关闭所有文件描述符,但你必须指定 close_fds=TruePopen


17.1.5. 笔记

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

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

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