【python】os.systemはもう古い!?subprocessでコマンドを実行しよう!

os.system()はもう使わない!subprocess()の使い方!今回は、pythonでunixコマンドを使う方法を紹介します。

今までの手段では、os.systemを用いてコマンドを実行しておりましたが、現在ではos.systemをはじめとした、いくつかのモジュールを統合したsubprocessが出てきております。

現在では、このsubprocessを使う事が推奨されております。その為、今回の記事では、

pythonでコマンドの使う方法がわからない
systemからsubprocessに変わったと言うけど、どのように使えばいいか分からない

という方へ向けて、

  • 【基礎】os.systemとは
  • 【基礎】subprocessとは
  • 【基礎】subprocessの使い方
  • 【応用】subprocess.run()について
  • 【応用】subprocess.popen()について

を解説いたします。ぜひ、最後までお付き合いください!

本記事を読む前に、Pythonがどんなプログラミング言語なのかをおさらいしておきたい人は次の記事を参考にしてください。

→ Pythonとは?特徴やできること、活用例をわかりやすく簡単に解説

なお、その他のPythonの記事についてはこちらにまとめています。

目次

os.system()とは

os.systemとは、unixコマンドをpython上で記述する為にある、従来のモジュールです。os.systemを使うには、osをインポートする必要があります。

ここで、os.systemを使う一例として、現在のディレクトリの中身を確認する”ls”コマンドを使う方法を確認しましょう!

#! /usr/bin/env python
import os

os.system("ls")

これで、unixコマンドの”ls”と同じ結果をpythonで実行できます。

subprocess()とは

今度は、os.systemやos.spawn*といったモジュールや関数を置き換えることを目的にしたモジュールである、subprocessについて説明します。subprocessは冒頭で説明した通り、os.systemを統合することを目的としたモジュールです。

コマンドを使う際の役割はos.systemと大差ありませんが、使い方が異なります。以降では、その使い方を説明致します。

subprocess()の使い方

まずはじめに、subprocessを使うにはsubprocessをインポートする必要があります。そこから更に、目的に応じて呼び出す関数が異なります。ここではまず3つの関数の使い方を紹介します。

subprocess.call()

subprocess.call()は、シンプルにただコマンドを実行したい時に使います。使い方はos.systemとほぼ同様で、使いたいコマンドを引数に入力するだけです。

また、コマンドの実行が正常に完了した際の戻り値は0となります。それでは、実際の例を確認してみましょう。

#! /usr/bin/env python

import subprocess

subprocess.call("ls")

os.system同様、”ls”コマンドを実行できたかと思います。

subprocess.check_call()

コマンドが正常に実行できたかどうか確認し、処理を分岐させたい場合はsubprocess.check_call()を使います。

これはコマンドを実行する際、失敗すると”CalledProcessError”を返す為、try-except処理をする事が可能となります。実装例は以下のようになります。

#! /usr/bin/env python

import subprocess

try:
    subprocess.check_call("ls")
except:
    print("subprocess.check_call() failed")

このように、try-exceptによって実行したコマンドが例外を出した場合の対応も可能となります。なお、try-exceptについて詳しく知りたい方は、以下を参照してください。

subprocess.check_output()

続いて、subprocess.check_output()を紹介します。こちらの関数は、コマンドを実行した際の出力を返します。

実行した際の出力を返すので、例えば”ls”を実行しても、その場では標準出力等には表示されず、print()をしなければ表示されないままとなります。

更に、CalledProcessErrorもあがってくるので例外処理も可能です。こちらも実行例を確認してみましょう。

#! /usr/bin/env python

import subprocess

res = subprocess.check_output("ls")

print("check_output() result: " + str(res))

これを実行すると、printするまで”ls”コマンドが標準出力へ出力されていない事がわかります。

コマンドに引数をつけたい場合

コマンドを実行する時には、引数をつけて実行したい場合もあるかと思います。そんな時は、以下のように実装しましょう。

#! /usr/bin/env python

import subprocess

command = ["ls", "-l"]

subprocess.call(command)

リストに格納する事で実行できました!もちろん、subprocess.call()の引数にリストを直接入力しても実行可能です。

subprocess.run()について

Python3.5以降では、subprocess関連のコマンドはsubprocess.run()を使う事が推奨されています。subprocess.run()は、subprocessにおけるすべての用法を扱うことが可能となっています。

引数は沢山あるのですが、よく使われる呼び出し方を紹介します。

#! /usr/bin/env python

import subprocess
import sys

command = ["ls", "-l"]

res = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

sys.stdout.buffer.write(res.stdout)

上記のコードについて説明すると、”command”にはコマンドと引数を入れたリストが入っています(コマンドの文字列だけでも可能です)。”stdout=subprocess.PIPE”は標準出力を取得したい場合につけます。check_outputと同じような感覚で使えます。

ただし、ここで返ってくるのはバイト列となるので注意です。print()したい場合は、”sys”をインポートし、”sys.stdout.buffer.write(res.stdout)”と記述しましょう。

最後に”stderr=subprocess.STDOUT”は標準エラー出力が標準出力と同じハンドルに出力されます。

つまり、今回の場合は”res”にエラーが出力されるので、
“sys.stdout.buffer.write(res.stdout)”の箇所まで、エラーを出力させなくする事ができます。

また、ここで”stderr=subprocess.STDOUT”を抜くと、標準エラーの場合はエラーが出た時点で出力されてしまいます。

subprocess.Popen()について

外部のプログラムを実行する時などでしばしばあるのですが、子プログラムの終了を待たずに次の処理を行いたい場合には、subprocess.Popen()を使います。

subprocess.Popen()が具体的にどのように処理されるのか、以下のコードから確認してみましょう。まずは親プログラムにあたるtest.pyです。

#! /usr/bin/env python

import subprocess

print("Parent Script Start")

command = ["python", "test2.py"]

subprocess.Popen(command)

print("Parent Script End")

続いて子プログラムに当たるtest2.pyが以下になります。

#! /usr/bin/env python

print("Child Script Start")
print("Child Script End")

これらのコードを実行するとどうのように処理されるでしょうか?まずはじめに、Popen()を使用せずにcall()で実行すると、

Parent Script Start
Child Script Start
Child Script End
Parent Script End

このようになります。

しかしPopen()を使ったコードでは、

Parent Script Start
Parent Script End
Child Script Start
Child Script End

処理の順番が変わりました。親プログラムが子プログラムを待たずに次の処理を実行している事がわかるかと思います。

まとめ

いかがでしたでしょうか?今回の記事では、

  • 【基礎】os.systemとは
  • 【基礎】subprocessとは
  • 【基礎】subprocessの使い方
  • 【応用】subprocess.run()について
  • 【応用】subprocess.popen()について

を解説いたしました!

os.systemはsubprocessに統合され、今後は使われなくなっていくかと思います。

ここで基本的な使い方だけでも覚えていって、いざという時に困らないよう備えておきましょう!

この記事を書いた人

1991年生まれ。双子座。
理系大学で認証システムを学んだ後、アプリ開発者となる。
新しく学ぶ人に寄り添った記事を心がけて執筆します。
芸術が好き。いつか猫と暮らすのが夢。

目次