Python子进程捕获输出
本文的主要目的是演示如何在Python中捕获、存储和显示一个Subprocess
的输出。
Python子进程捕获输出
Subprocess
是一个内置的Python模块,预先安装在Python的安装文件中。它用于通过创建新的进程来运行新的代码和应用程序,其中给定的任务(根据所传递的内容)与它的进程分开执行。
使用Subprocess
的主要优点之一是,它允许我们从当前编写的程序中启动新的程序。
运行这种程序的一个例子是,如果你想从Git仓库克隆一些项目,或者也许执行一个C++编译器二进制文件,执行其特定的任务。
考虑我们要执行一个用C++编写的程序,其代码如下。
#include <iostream>using namespace std;
int main()
{
int rows = 5, count = 0, count1 = 0, k = 0;
for(int i = 1; i <= rows; ++i)
{
for(int space = 1; space <= rows-i; ++space)
{
cout << " ";
++count;
}
while(k != 2*i-1)
{
if (count <= rows-1)
{
cout << i+k << " ";
++count;
}
else
{
++count1;
cout << i+k-2*count1 << " ";
}
++k;
}
count1 = count = k = 0;
cout << endl;
}
return 0;
}
其中独立打开执行,会有如下输出:
现在我们执行用Python编写的程序的编译二进制文件。
import subprocess
p2 = subprocess.Popen("program\pyramid.exe")
print(p2)
输出:
<Popen: returncode: None args: '....\program\pyramid.exe>
1
2 3 2
3 4 5 4 3
4 5 6 7 6 5 4
5 6 7 8 9 8 7 6 5
从上面的代码中可以看出,很明显,我们没有得到字符串,而是得到了Popen
的实例,这并不是理想的情况,因为我们需要字符串的输出来对输出进行处理或用于其他目的。
必须注意的是,我们看到的金字塔输出不是打印名为p2
的变量的结果,而是使用Popen
的执行程序的输出。
这个问题可以用多种方法来解决,下面将介绍其中的一些方法。
方法1:使用check_output
,在Python中捕获subprocess
的输出
考虑一下下面的代码:
from subprocess import check_output
out = check_output(["program\pyramid.exe"])
print(out)
输出:
b' 1 rn 2 3 2 rn 3 4 5 4 3 rn 4 5 6 7 6 5 4 rn5 6 7 8 9 8 7 6 5 rn'
输出是字节形式的,使用decode()
函数可以很容易地转换为字符串。
print(out.decode('utf-8'))
输出:
这就是我们在名为out
的字符串变量中所期望的输出。
check_output()
函数运行我们想要的命令,并以字节字符串的形式返回所执行程序的命令输出。
然后我们可以使用decode()
方法将该字节字符串转换为普通字符串。decode()
参数的编码参数可以根据输出类型的不同而不同。
在我们的案例中,它是utf-8
,但在不同的程序和不同的操作系统中,它可以有所不同。
方法2:使用Popen.communicate
,在Python中捕获subprocess
的输出。
考虑一下下面的代码:
import subprocess
pipe = subprocess.Popen("\program\pyramid.exe", stdout=subprocess.PIPE)
text = pipe.communicate()[0]
print(text)
输出:
b' 1 rn 2 3 2 rn 3 4 5 4 3 rn 4 5 6 7 6 5 4 rn5 6 7 8 9 8 7 6 5 rn'
像以前一样,返回一个字节字符串,可以很容易地使用decode()
函数返回。
print(text.decode('utf-8'))
输出:
不使用check_output
,我们也可以使用Popen.communicate()
方法,check_output
的主要优点之一是它允许人们将stdout
和stderr
重定向到我们想要的变量。
它的工作原理是:Popen
返回一个stdout
和stderr
的元组,所以当你访问 [0]
stdout
你也可以做text, err = pipe.communicate()
,然后text
,就可以得到需要的东西。
就像check_output
,Popen.communicate()
也会返回一个字节字符串,在把兼容和合适的编码方案传给decode
方法后,可以很容易地用decode
方法转换为普通字符串。