python subprocess 試験対策
コマンドを使いたいときに便利なsubprocess
自分は最近PowerPointを操作するアプリを作った際に、
PowerPointの操作はC#プログラムで、
PowerPoint操作以外の部分はPythonで
という感じでアプリを作った際にsubprocessを使いました。
Pythonでsubprocessを使って、C#で作ったプログラム.exeに対してコマンドライン引数渡して実行みたいな
ってことで、今回はsubprocessについて
まずは ls コマンドを実行してみたいと思います。
import subprocess
subprocess.run(args=["ls", "-l"])
結果
-rw-r--r-- 1 fuji staff 241 10 14 21:46 test_subprocess.py
引数argsにlistでコマンドを渡してあげれば実行してくれます。
標準入力を求めるコマンドに対して
wcコマンドっていう、文字数をカウントしてくれるコマンドがあるんですが、ターミナルでwcってだけ打つと文字入力待機状態になるわけなんですが、そういったコマンドに対して、文字を送ることもできます。
command = subprocess.run(args=["wc"],
input="hello",
encoding="utf-8",
stdout=subprocess.PIPE)
print(command.stdout)
>>>結果
0 1 5
input="hello"
input引数は、外部コマンドに渡す標準入力(データ)を指定します。この場合、コマンドに渡される標準入力の内容は、文字列 "hello" です。
つまり、wcコマンドがhelloという文字列を受け取り、それを基に文字数や単語数を数えます。
encoding="utf-8"
encoding引数は、標準入力と標準出力を文字列として扱う際のエンコーディングを指定します。
ここではutf-8エンコーディングを指定しているため、Pythonは標準出力や標準入力をUTF-8文字列として処理します。これが指定されていない場合、デフォルトではバイト列(bytes型)として扱われるので、文字列として処理するためにエンコーディングを明示しています。
stdout=subprocess.PIPE
stdout引数は、コマンドの標準出力をどのように処理するかを指定します。subprocess.PIPEを指定すると、外部コマンドの標準出力をPythonプログラム内でキャプチャして利用できます。
このコードでは、wcの結果をキャプチャして、後で利用できるようにしています。
ってことで重要なところとしては
文字列渡すときはencoding指定してね
結果を受け取りたいときはsubprocess.PIPEっていうのをstdoutに渡してね
ってところです。
1. stdout があるなら stdin もある?
stdin もあります。stdoutがコマンドの出力をキャプチャするために使われるのに対して、stdinはコマンドに入力を提供するために使います。
例えば、コマンドにファイルの内容を入力として渡す場合、次のように stdin を使います:
import subprocess
with open('input.txt', 'r') as input_file:
# 'wc' コマンドにファイルの内容を渡す
command = subprocess.run(['wc'], stdin=input_file, stdout=subprocess.PIPE, encoding='utf-8')
print(command.stdout)
stdoutにファイルを渡せばファイルに出力を書き込んでくれます。
ようは
ls -l > sample.txt
をする感じです。
import subprocess
# 'ls -l' コマンドの結果を 'output.txt' に書き込む
with open('output.txt', 'w') as output_file:
subprocess.run(['ls', '-l'], stdout=output_file)
コマンドが成功したかどうか
import subprocess
command = subprocess.run(args=["ls"])
print(command.returncode)
>> 0
command = subprocess.run(args=["ls", "sample"]) # 存在しないディレクトリを指定
print(command.returncode)
>> 1
returncodeで取得できて、成功は 0, エラーは1
これでコマンドの成功失敗を判定することもできるし、ほかにも引数check=Trueにすることで例外を出してくれます。
import subprocess
command = subprocess.run(args=["ls", "sample"], check=True) # 存在しないディレクトリを指定
print(command.returncode)
>>>
Traceback (most recent call last):
File "/**********", line 9, in <module>
command = subprocess.run(args=["ls", "sample"], check=True) # 存在しないディレクトリを指定
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/python@3.12/3.12.4/Frameworks/Python.framework/Versions/3.12/lib/python3.12/subprocess.py", line 571, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['ls', 'sample']' returned non-zero exit status 1.
非同期処理で行いたい
subprocess.Popen の使い方
subprocess.run ではなく、もっと細かい制御が必要な場合は subprocess.Popen を使う。例えば、非同期でプロセスを実行し、後からプロセスの状態を確認したり、プロセスを停止したりできます。
import subprocess
# 非同期で 'sleep 5' コマンドを実行
process = subprocess.Popen(['sleep', '5'])
# 他の処理を並行して行える
print("上記を実行しつつ次の処理を実行します")
subprocess.run(args=["echo", "Hello, World!"])
# プロセスの終了を待機
process.wait()
print("プロセスが終了しました")
実行するとわかるんですが、
コード上はsleepが先に実行されるので、5秒待機してからHello, World!が出るかと思いきや、すぐにHello,World!が出力され、5秒待機後にプロセスが終了します。
補足としてwait()を使わないと、sleepコマンドが終わる前にプログラムが終了しちゃいます。
waitは実行中のプロセスが終わるまで待機するメソッドです。
この記事が気に入ったらサポートをしてみませんか?