実行中に Python サブプロセスが Stdout を読み取る
-
実行中に Python サブプロセスが
stdout
を読み取る -
アプローチ 1: Python での実行中に
check_call
を使用してsubprocess
のstdout
を読み取る -
アプローチ 2: プロセスをポーリングして、Python で実行中に
subprocess
のstdout
を読み取る
この記事の主な目的は、Python で実行されている subprocess
の stdout
を読み取る方法を示すことです。
実行中に Python サブプロセスが stdout
を読み取る
他の多くの組み込みモジュールと同様に、Subprocess
も組み込みモジュールであり、通常の
Python インストールでプリインストールされています。
これは主に、新しいプロセスでタスク、プロセス、およびプログラムを実行し、特定の一連のタスクを実行して結果を返したい場合に使用されます。
広く使用されている多くの理由の 1つは、外部プログラムと実行可能ファイルをプログラムから直接別のプロセスとして実行できることです。
Subprocess
ライブラリを使用してプログラムを実行している間、その外部プログラムの出力をリアルタイムで表示する必要がある場合があります。 これは、プログラムがリアルタイムで、短時間の計算に依存する場合など、さまざまな理由で要件になる可能性があります。
次のプログラムを検討してください。
import subprocess
def execute(command):
process = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
output = process.communicate()[0]
exitCode = process.returncode
if exitCode == 0:
return output
else:
raise Exception(command, exitCode, output)
if __name__ == "__main__":
print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))
出力:
Folder PATH listing
Volume serial number is 0213-B7F2
C:.
+---DRIVERS
¦ +---bluetooth
¦ +---U1BLT07AVVASDSAP
¦ +---Custom
¦ ¦ +---EULA
¦ +---Win64
¦ +---LD
¦ +---svcpack
+---flutter
¦ +---.git
¦ ¦ +---hooks
¦ ¦ +---info
¦ ¦ +---logs
¦ ¦ ¦ +---refs
¦ ¦ ¦ +---heads
¦ ¦ ¦ +---remotes
¦ ¦ ¦ +---origin
¦ ¦ +---objects
¦ ¦ ¦ +---info
¦ ¦ ¦ +---pack
¦ ¦ +---refs
¦ ¦ +---heads
¦ ¦ +---remotes
¦ ¦ ¦ +---origin
¦ ¦ +---tags
¦ +---.github
¦ ¦ +---ISSUE_TEMPLATE
¦ ¦ +---workflows
¦ +---.idea
¦ ¦ +---runConfigurations
...
プログラムで出力を確認できますが、リアルタイムでは確認できません。 出力は、コマンド全体 (この場合は tree
) の実行が終了した後にのみ表示されます。
プログラム (またはコマンド) が Subprocess
コマンドを使用して別のプロセスで実行されるまで、出力には何も表示されません。
私たちの場合、出力をリアルタイムで取得する必要があるため、別のソリューションを作成する必要があります。これは、stdout
に書き込まれたプログラムの出力を表示するソリューションです。
解決策には複数の方法がありますが、その一部を以下に示します。
アプローチ 1: Python での実行中に check_call
を使用して subprocess
の stdout
を読み取る
次のコードを検討してください。
import subprocess
import sys
def execute(command):
subprocess.check_call(
command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT
)
if __name__ == "__main__":
print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))
出力:
Folder PATH listing
Volume serial number is 0213-B7F2
C:.
├───DRIVERS
│ └───bluetooth
│ └───U1BLT0720US14CMP
│ ├───Custom
│ │ └───EULA
│ └───Win64
│ ├───LD
│ └───svcpack
├───flutter
│ ├───.git
│ │ ├───hooks
│ │ ├───info
│ │ ├───logs
│ │ │ └───refs
│ │ │ ├───heads
│ │ │ └───remotes
│ │ │ └───origin
│ │ ├───objects
│ │ │ ├───info
│ │ │ └───pack
│ │ └───refs
│ │ ├───heads
│ │ ├───remotes
│ │ │ └───origin
│ │ └───tags
│ ├───.github
│ │ ├───ISSUE_TEMPLATE
│ │ └───workflows
│ ├───.idea
│ │ └───runConfigurations
│ ├───.pub-cache
│ │ ├───hosted
│ │ │ └───pub.dartlang.org
│ │ │ ├───.cache
...
主な要件がプログラムの出力をリアルタイムで出力することである場合、check_call
を使用してこれを実現できます。 このシンプルでクリーンでエレガントなソリューションは、出力のみを印刷する必要がある場合など、非常に単純なプログラムにとって簡潔で完璧
です。
check_call
はパラメーターの受け渡しもサポートしているため、プログラムが機能するために引数が必要な場合は、手間をかけずに簡単に関数に渡すことができます。 このメソッドは、プログラムが完了するまで待機します。
プログラムの完了に基づいて、メソッドは戻ります。 それ以外の場合は、CalledProcessError
例外が発生します。 CalledProcessError
には、returncode
属性を使用してアクセスできる失敗の戻りコードがあります。
上記のコードでは、command
が check_call
メソッドに渡されます。このメソッドには、実行するコマンド (またはプログラム) が含まれています。
シェルを使用してプロセスを実行するために shell
パラメータは true
に設定され、プロセスの stdout
はプログラムの stdout
に設定されているため、stdout
に直接書き込みます。 stdout
で発生する変更を確認します。
最後に、生成されたプロセスの stdout
に stderr
が設定されます。
アプローチ 2: プロセスをポーリングして、Python で実行中に subprocess
の stdout
を読み取る
次のコードを検討してください。
import subprocess
import sys
def execute(command):
process = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
# Poll process for new output until finished
while True:
nextline = process.stdout.readline().decode("unicode_escape")
if nextline == "" and process.poll() is not None:
break
sys.stdout.write(nextline)
sys.stdout.flush()
output = process.communicate()[0]
exitCode = process.returncode
if exitCode == 0:
return output
else:
raise Exception(command, exitCode, output)
if __name__ == "__main__":
print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))
出力:
...
¦ ¦ ¦ ¦ ¦ +---UuidUtil
¦ ¦ ¦ ¦ +---example
¦ ¦ ¦ ¦ +---lib
¦ ¦ ¦ ¦ +---test
¦ ¦ ¦ +---vector_math-2.1.2
¦ ¦ ¦ ¦ +---benchmark
¦ ¦ ¦ ¦ +---bin
¦ ¦ ¦ ¦ +---lib
¦ ¦ ¦ ¦ ¦ +---src
¦ ¦ ¦ ¦ ¦ +---vector_math
¦ ¦ ¦ ¦ ¦ ¦ +---third_party
¦ ¦ ¦ ¦ ¦ +---vector_math_64
¦ ¦ ¦ ¦ ¦ ¦ +---third_party
¦ ¦ ¦ ¦ ¦ +---vector_math_geometry
¦ ¦ ¦ ¦ ¦ ¦ +---filters
¦ ¦ ¦ ¦ ¦ ¦ +---generators
¦ ¦ ¦ ¦ ¦ +---vector_math_lists
¦ ¦ ¦ ¦ ¦ +---vector_math_operations
¦ ¦ ¦ ¦ +---test
¦ ¦ ¦ ¦ +---tool
¦ ¦ ¦ +---video_player-2.2.11
¦ ¦ ¦ ¦ +---android
¦ ¦ ¦ ¦ ¦ +---gradle
...
Subprocess
を使用して生成されたプログラムの出力が stdout
に書き込まれるとすぐに印刷されるようにするには、プロセスをポーリングして出力し、プログラムの stdout
の stdout
の最後の行を読み続ける必要があります。
無限
ループでは、生成されたプロセスの出力を readline()
を使用して読み取り続けます。 出力はエンコードされているため、適切に表現するにはデコードする必要があります (この場合は utf-escape
)。
これは、decode
メソッドを使用して、関連するエンコード スキームを渡すことで実行できます。
プログラムの実行が終了したら、無限
ループもエスケープする必要があります。 これを行うには、次の 2つのことを確認します。
- 現在の
stdout
行は空です。 - プロセスが終了または終了しました。
これは、最初の条件の単純な文字列比較と、プロセスが終了したかどうかを確認する poll()
メソッドを使用して、非常に簡単に実行できます。 プログラムが終了した場合は、returncode
を返します。 それ以外の場合、None
を返します。
None
との単純な比較でも、プログラムの実行が終了したかどうかに関する情報を得ることができます。
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn