記事ディレクトリ
この記事の主な目的は、Python でサブプロセスの出力を取得、保存、表示する方法を説明することです。
Python サブプロセス キャプチャ出力
サブプロセスは、Python インストール時にプリインストールされる組み込み Python モジュールです。これは、特定のタスク (渡された内容に従って) がそのプロセスとは別に実行される新しいプロセスを作成することによって、新しいコードやアプリケーションを実行するために使用されます。
Subprocess を使用する主な利点の 1 つは、現在作成されているプログラム内から新しいプログラムを開始できることです。
このようなプログラムを実行する例としては、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 でサブプロセスの出力を取得する
次のコードを考えてみましょう。
from subprocess import check_output
out = check_output(["program\\pyramid.exe"])
print(out)
出力:
b' 1 \r\n 2 3 2 \r\n 3 4 5 4 3 \r\n 4 5 6 7 6 5 4 \r\n5 6 7 8 9 8 7 6 5 \r\n'
出力はバイト単位であり、decode()
関数を使用して簡単に文字列に変換できます。
print(out.decode('utf-8'))
出力:
これは、out という名前の文字列変数の目的の出力です。
check_output()
この関数は必要なコマンドを実行し、実行されたプログラムのコマンド出力をバイト文字列として返します。
次に、decode()
このメソッドを使用してバイト文字列を通常の文字列に変換できます。decode()
パラメータのエンコードパラメータは出力タイプによって異なる場合があります。
この場合は utf-8 でしたが、プログラムや OS によって異なる場合があります。
方法 2: Popen.communicate を使用して Python でサブプロセスの出力をキャプチャする
次のコードを考えてみましょう。
import subprocess
pipe = subprocess.Popen("\\program\\pyramid.exe", stdout=subprocess.PIPE)
text = pipe.communicate()[0]
print(text)
出力:
b' 1 \r\n 2 3 2 \r\n 3 4 5 4 3 \r\n 4 5 6 7 6 5 4 \r\n5 6 7 8 9 8 7 6 5 \r\n'
前と同様に、バイト文字列を返します。これは、decode() 関数を使用して簡単に返すことができます。
print(text.decode('utf-8'))
出力:
check_output を使用する代わりに、Popen.communicate()
このメソッドを使用することもできます。check_output の主な利点の 1 つは、stdout と stderr を必要な変数にリダイレクトできることです。
Popen は stdout と stderr のタプルを返すため、[0] にアクセスすると stdout を取得するだけになります。text を実行することもできます。err = pipe.communicate()
テキストには必要なものが含まれます。
check_output と同様に、Popen.communicate()
互換性のある適切なエンコード スキームを decode メソッドに渡した後、decode メソッドを使用して通常の文字列に簡単に変換できるバイト文字列も返します。