kanta's spike

Pythonで外部プロセスを実行し、その外部プロセスの標準入力を使って、Pythonから情報を与えたい。

ただし、Popen.communicate(input)を使うと、 プロセス終了まで処理がブロックされるため、標準入力をプロセスに非同期で渡したい。

解決策

subprocess.Popenstdinに直接データを書き込めば良い。

以下は、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() を利用してください。

参考

作成日: 2024/01/19