Pythonで外部プロセスを実行し、その外部プロセスの標準入力を使って、Pythonから情報を与えたい。
ただし、Popen.communicate(input)を使うと、 プロセス終了まで処理がブロックされるため、標準入力をプロセスに非同期で渡したい。
解決策
subprocess.Popenのstdin
に直接データを書き込めば良い。
以下は、cat -に対して、標準入力からtest1\ntest2\ntest3を渡している。
# spike2.py
import subprocess
import time
def main():
proc = subprocess.Popen(
"cat - ",
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# 標準入力に直接書き込む
proc.stdin.write("test1\ntest2\ntest3")
proc.stdin.close() # クローズしないとプロセスが入力待ちのままになる
# プロセスが終了するまで待つ
# 終了を待つだけなら`proc.wait()`で良い
while proc.poll() is None:
# 必要ならプロセス実行中に、ここで別の処理を行う
time.sleep(1)
print(f"returncode: {proc.poll()}")
print("stdout:")
print(proc.stdout.read())
if __name__ == "__main__":
main()
実行結果は以下となる。
$ python spike2.py
returncode: 0
stdout:
test1
test2
test3
ただし、以下の警告がある。
📄
警告
.stdin.write, .stdout.read, .stderr.read を利用すると、別のパイプの OS パイプバッファーがいっぱいになってデッドロックが発生する恐れがあります。これを避けるためには communicate() を利用してください。