LoginSignup
2
1

More than 1 year has passed since last update.

Pythonのsubprocessでコマンド標準出力を取得しつつコンソールにも表示したい

Last updated at Posted at 2022-07-20

はじめに

Pythonのsubprocessでコマンド実行時

  • その標準出力を文字列として取得したい
  • 同時に、コンソールにもリアルタイム表示したい

といった場合の実装例です。

仕様

  • MyConsoleクラス
    • パイプを作成し、読込み用と書込み用のファイルディスクリプタをクラスメンバーに指定
    • スレッドを作成し、下記処理を行う
      • パイプにデータ存在するまで読込む(4KB単位)
      • 取得データをシステム標準出力に書き込む
      • 同時に、データを結果文字列にも追加
  • subprocess.run()でコマンド実行
    • stdoutパラメータにMyConsole書込み用ファイルディスクリプタを指定

コード

Windowsのサンプルコードです。

test_console.py
import threading
import os
import sys
import subprocess

class MyConsole:
    def __init__(self):
        self.result_str = ""
        self.rfd, self.wfd = os.pipe()
        thread = threading.Thread(target=self._read)
        thread.daemon = True
        thread.start()

    def _read(self):
        while True:
            data = os.read(self.rfd, 4096)
            if data is None:
                break
            data_str = data.decode()
            sys.stdout.write(data_str)
            self.result_str += data_str
        os.close(self.rfd)
        os.close(self.wfd)
    
    def get(self):
        return self.result_str

if __name__ == "__main__":
  con = MyConsole()
  print("==== ここから標準出力のコンソール表示")
  subprocess.run(["ping", "127.0.0.1", "-n", "3"], shell=True, stdout=con.wfd)
  print("==== ここまで標準出力のコンソール表示\n")
  print("==== ここから標準出力から取得した結果文字列")
  print(con.get())
  print("==== ここまで標準出力から取得した結果文字列")

実行結果

> python .\test_console.py
==== ここから標準出力のコンソール表示

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
==== ここまで標準出力のコンソール表示

==== ここから標準出力から取得した結果文字列

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

==== ここまで標準出力から取得した結果文字列

同じ内容が、コンソールに表示されつつ、
結果文字列にも、保存されます。

Linuxの場合

サンプルコードで、下記1行を書き換えてください。

  • 修正前
  subprocess.run(["ping", "127.0.0.1", "-n", "3"], shell=True, stdout=con.wfd)
  • 修正後
  subprocess.run(["ping", "127.0.0.1", "-c", "3"], stdout=con.wfd)

おわりに

Pythonのsubprocessで標準出力を制御してみました。
subprocess使用時に、ご参考になれば何よりです。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1