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 での実行結果 |
---|---|---|---|---|
なし | 文字列 | True | OK | OK |
なし | 文字列 | False | OK | OK |
あり | 文字列 | True | OK | OK |
あり | 文字列 | False | OK | NG |
あり | リスト | True | OK | 引数が使用されず |
あり | リスト | False | OK | OK |
Windows ではコマンドのデータ型と shell への設定値を気にする必要は無いですが、Linux系OSでは文字列を使用する場合には True を、リストを使用する場合には False を指定する必要があることが解ります。
動作確認に使用したコード
下記コードを 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 でシェアして頂ければ幸いです。