2021年07月30日 更新

subprocessでPythonからLinuxコマンド実行

どうも、クラゲです。
Pythonプログラム上でLinuxコマンドを実行したいときに役立つsubprocessです。例えば、効果音の音声出力や他のスクリプトを実行させるなどに使えます。

subprocess でコマンド実行

PythonプログラムでLinuxコマンドを実行する方法として os.system がありますが、これは古い方式でそのうち subprocess に置き換えられる可能性があるため、こちらを使います。 https://docs.python.org/ja/3/library/subprocess.html

例えばlsコマンドをPythonプログラムの中で使いたいとします。
Pythonプログラムでは以下のように書きます。

import subprocess
subprocess.run(['ls'])

今度はオプション付のコマンド例です。
-lを付けて、ls -lにするとファイルの詳細が表示されます。
Pythonプログラムでは以下のように書きます

import subprocess
subprocess.run(['ls', '-l'])

さらにオプションをついた場合の例です。
-Sを付けて、ls -l -Sにするとファイルサイズの大きい順にソートされます。
Pythonプログラムでは以下のように書きます。

import subprocess
subprocess.run(['ls', '-l', '-S'])

大体分かりましたね?
スペースを区切りとして、リスト化したものを引数に渡せばOKです。

なお、echo "hello jellyfish"のように、Linuxコマンドの引数にクォーテーションがある場合(別の言い方をするとスペースを含んでいる引数の場合)はクォーテーションは不要となります。

import subprocess
subprocess.run(['echo', 'hello jellyfish'])

同期と非同期(run と Popen)

先程の subprocess.run は同期処理です。
「同期処理」とは、処理が終わってから次の処理に進むという意味です。
先程のlsコマンドだと一瞬で処理が終わってしまうため、音声出力を行うコマンド aplay で試してみましょう。2つの音声ファイル a.wavb.wav を用意して以下を実行します。数秒程度の長さのファイルがいいと思います。

import subprocess

subprocess.run(['aplay', 'a.wav'])
subprocess.run(['aplay', 'b.wav'])

a.wavの再生が終わってから b.wavの再生が始まったと思います。
一方で subprocess.Popen を使うと非同期処理が行えます。
「非同期処理」は、処理が終わっているかに関係なく、次の処理に進むという意味です。

import subprocess

subprocess.Popen(['aplay', 'a.wav'])
subprocess.run(['aplay', 'b.wav'])

両方ともほぼ同時に再生されたかと思います。
このように非同期で処理したい箇所は run ではなく Popen を使ってください

プロセスを強制終了(kill)

非同期で実行させたけど、何らかの処理があった場合に止めたい場合があると思います。
ここでは c.wav という数十秒以上の曲を準備して実行してみてください。

import subprocess

proc = subprocess.Popen(['aplay', 'c.wav'])
input() #入力待ち
proc.kill()

エンターキーが押されると、c.wavの再生は強制終了したと思います。
このように、subprocess.Popenの戻り値を取得しておけば、必要なタイミングでkill関数を使うことで強制終了させることができます。

以上、subprocessでした!