Popen 具有更大的灵活性

subprocess.call 相比,使用 subprocess.Popen 可以对启动的进程进行更细粒度的控制。

启动子流程

process = subprocess.Popen([r'C:\path\to\app.exe', 'arg1', '--flag', 'arg'])

Popen 的签名与 call 函数非常相似; 但是,Popen 将立即返回,而不是像 call 那样等待子进程完成。

等待子进程完成

process = subprocess.Popen([r'C:\path\to\app.exe', 'arg1', '--flag', 'arg'])
process.wait()

从子进程读取输出

process = subprocess.Popen([r'C:\path\to\app.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# This will block until process completes
stdout, stderr = process.communicate()
print stdout
print stderr

对正在运行的子进程的交互式访问

即使子进程尚未完成,你也可以在 stdinstdout 上进行读写。当在另一个程序中自动执行功能时,这可能很有用。

写入子进程

process = subprocess.Popen([r'C:\path\to\app.exe'], stdout = subprocess.PIPE, stdin = subprocess.PIPE)

process.stdin.write('line of input\n') # Write input

line  = process.stdout.readline() # Read a line from stdout

# Do logic on line read.

但是,如果你只需要一组输入和输出,而不是动态交互,则应使用 communicate() 而不是直接访问 stdinstdout

从子进程读取流

如果你想逐行查看子流程的输出,可以使用以下代码段:

process = subprocess.Popen(<your_command>, stdout=subprocess.PIPE)
while process.poll() is None:
    output_line = process.stdout.readline()

如果子命令输出没有 EOL 字符,则上述代码段不起作用。然后,你可以按字符读取输出字符,如下所示:

process = subprocess.Popen(<your_command>, stdout=subprocess.PIPE)
while process.poll() is None:
    output_line = process.stdout.read(1)

指定为 read 方法的参数的 1 告诉 read 在时间读取 1 个字符。你可以指定使用不同的数字读取所需的字符数。负数或 0 告诉 read 读取单个字符串,直到遇到 EOF( 参见此处 )。

在上面的两个片段中,process.poll() 都是 None,直到子进程完成。一旦没有更多输出要读取,这用于退出循环。

相同的过程可以应用于子过程的 stderr