【Python】subprocess.Popen 使用時の注意点(Windows と Linux での挙動の違い)

5 min

Chromebook の Linux 開発環境では Python の開発が出来ます。Python で非同期でコマンドラインを実行する際は subpress.Popen を使用します。Windows では問題無く動作したにも関わらず Linux系OSでは「No such file or directory」というエラーが発生することがあると思います。本記事では subprocess.Popen 使用時の注意(OSによる挙動の違い)を説明します。

広告_零号機

subprocess.Popen による Python の非同期処理サンプル

Popen について

詳しくはマニュアルを参照していただきたいですが、ざっくりいうと、

subprocess を使用すると新しいプロセスを開始してコマンドを実行することが出来ます。

subprocess モジュールは新しいプロセスの開始、入力/出力/エラーパイプの接続、リターンコードの取得を可能とします。

マニュアル

そして、コマンドの実行結果を待つ場合は run を待たない(つまり非同期)場合は Popen を使用します。また、stdoutにファイルを指定することで実行結果をファイルに出力することが出来ます。

サンプルコード:子プロセスを開始して pip を実行し、実行結果を test_com_True.txt に書き込む

import subprocess
from subprocess import PIPE

def _popen_test_com_True():
    f = open("test_com_True.txt", "w")
    try:
        proc = subprocess.Popen("pip", shell=True, stdout=f, stderr=PIPE, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

subprocess.Popenの引数の使用イメージと注意ポイント

Popen では第一引数が実行コマンドになっていますが、引数付きのコマンドを実行する方法には下記の2つがあります。

  • 引数付きのコマンドを文字列として指定する →例)”pip list”
  • 引数をリストとして指定する →例)[“pip”, “list”]

そして、第二引数は shell という変数への設定値であり、実行するコマンドに合わせて Popen の shell への設定値を考慮する必要があります。

  • shell=True

しかし、この shell への設定値がOSごとに異なります。

Windows と Linux系OSでの引数による挙動の違い

Windows と Linux系OS での挙動の違いをまとめると以下のようになります。

コマンド
(引数の有無)
コマンド
(データ型)
shell
への設定値
windows
での実行結果
Linux系OS
での実行結果
なし文字列TrueOKOK
なし文字列FalseOKOK
あり文字列TrueOKOK
あり文字列FalseOKNG
ありリストTrueOK引数が使用されず
ありリストFalseOKOK
Popen のOSによる挙動の違い

Windows ではコマンドのデータ型と shell への設定値を気にする必要は無いですが、Linux系OSでは文字列を使用する場合には True を、リストを使用する場合には False を指定する必要があることが解ります。

どこで使用されるか解らないので
shell への設定値はLinux系OSに合わせることを推奨します。

動作確認に使用したコード

下記コードを Windows マシンと Linux系OSのマシン(Chromebookを使用)で動作させて確認しました。

import subprocess
from subprocess import PIPE

def _popen_test_com_True():
    f = open("test_com_True.txt", "w")
    try:
        proc = subprocess.Popen("pip", shell=True, stdout=f, stderr=PIPE, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

def _popen_test_com_False():
    f = open("test_com_False.txt", "w")
    try:
        proc = subprocess.Popen("pip", shell=False, stdout=f, stderr=PIPE, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

def _popen_test_args_str_True():
    f = open("test_args_str_True.txt", "w")
    try:
        proc = subprocess.Popen("pip list", shell=True, stdout=f, stderr=subprocess.STDOUT, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

def _popen_test_args_str_False():
    f = open("test_args_str_False.txt", "w")
    try:
        proc = subprocess.Popen("pip list", shell=False, stdout=f, stderr=subprocess.STDOUT, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

def _popen_test_args_list_False():
    f = open("test_args_list_False.txt", "w")
    try:
        proc = subprocess.Popen(["pip", "list"], shell=False, stdout=f, stderr=subprocess.STDOUT, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

def _popen_test_args_list_True():
    f = open("test_args_list_True.txt", "w")
    try:
        proc = subprocess.Popen(["pip", "list"], shell=True, stdout=f, stderr=subprocess.STDOUT, text=True)
        print("   success")
    except Exception as e:
        print(e)
        f.write('Exception occurred while code execution: ' + str(e))

if __name__ == "__main__":
    print("-- _popen_test_com_True --")
    _popen_test_com_True()
    print("-- _popen_test_com_False --")
    _popen_test_com_False()
    print("-- _popen_test_args_str_True --")
    _popen_test_args_str_True()
    print("-- _popen_test_args_str_False --")
    _popen_test_args_str_False()
    print("-- _popen_test_args_list_True --")
    _popen_test_args_list_True()
    print("-- _popen_test_args_list_False --")
    _popen_test_args_list_False()

まとめ

本記事では、 Popen の OSによる挙動の違いを説明しました。ご参考になりましたら twitter をフォローして SNS でシェアして頂ければ幸いです。

広告_零号機-エリア2
kewton

kewton

大学院卒業後、某大手SIerで10年以上SEとして従事。
社会人3年目までに基本情報・応用情報技術者、データベーススペシャリスト、簿記3級・2級を取得。
基幹系システム・IoTシステム開発のプロジェクト経験多数。AI活用システムの企画・プロト開発経験あり。
強みは、プロマネだけでなく自身で開発も実施してきたこと。
【扱える言語】
C#、java、python、javascript、Excel VBA
【扱えるDB】
oracle、sql server、postgreSQL、mongoDB

FOLLOW

カテゴリー:
関連記事

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA