Popen()
を使用するときにsubprocess
が実行可能ファイルを検索する方法について混乱しています。子プロセスへの絶対パスを指定すると機能しますが、相対パスを使用しようとしています。環境変数PYTHONPATHを設定すると、そのパスからインポートされたモジュールを取得でき、PYTHONPATHはsys.path
にありますが、subprocess.Popen
の動作には役立たないようです。また、sitecustomize.py
ファイルを編集して、PYTHONPATHをos.environ
に追加しようとしました。
# copy PYTHONPATH environment variable into PATH to allow our stuff to use
# relative paths for subprocess spawning
import os
if os.getenv('PYTHONPATH') is not None and os.getenv('PATH') is not none:
os.environ['PATH'] = ':'.join([os.getenv('PATH'), os.getenv('PYTHONPATH')])
pythonの起動時に、対話的に、ipythonを使用するか、コマンドラインからスクリプトを実行することにより、PYTHONPATHがos.environ
に正常に表示されることを確認しました。ただし、subrocess.Popen
stillは、実行可能ファイルを検索しません。env
kwargが指定されていない場合、親環境を継承することになっていると思いましたか?次にenv
明示的に、最初にos.getenv
のコピーを作成し、次にenv={'PATH': '/explicit/path/to/search/from'}
を指定するだけで、まだ実行可能ファイルが見つかりません。
例が私の問題をより明確に説明するのに役立つことを願っています:
/ dir/subdir1/some_executable
/dir/subdir2/some_script.py
# some_script.py
from subprocess import Popen, PIPE
spam, eggs = Popen(['../subdir1/some_executable'], stdout=PIPE, stderr=PIPE).communicate()
/dir/subdir2
にいるときにpython some_script.py
を実行すると動作しますが、/dir
にあるときにpython subdir2/some_script.py
を実行すると、/dir/subdir2
がos.environ['PATH']
にある場合、サブプロセスはOSError: [Errno 2] No such file or directory
をスローします。
PATH
とPYTHONPATH
の性質について少し混乱しているように見えます。
PATH
は、実行可能ファイルを検索する場所をOSシェルに指示する環境変数です。
PYTHONPATH
は、Pythonインタープリターにインポートするモジュールを検索する場所を指示する環境変数です。実行ファイルを見つけるsubprocess
とは何の関係もありません。
基礎となる実装の違いにより、subprocess.Popen
は、Windows以外のシステムでデフォルトでパスのみを検索します(Windowsには常に検索するシステムディレクトリがいくつかありますが、PATH
処理とは異なります)。パスをスキャンする唯一の信頼できるクロスプラットフォームの方法は、Shell=True
はサブプロセス呼び出しに対応していますが、独自の問題があります(詳細は Popen
のドキュメント )
ただし、主な問題は、単純なファイル名ではなくPopen
にパスフラグメントを渡すことです。そこにディレクトリセパレーターがあるとすぐに、Windows以外のプラットフォームでもPATH
検索を無効にします(たとえば、 execファミリー関数)についてはLinuxのドキュメントを参照してください )。
Subprocess.Popenの相対パスは、システムPATHの要素ではなく、現在の作業ディレクトリを基準にして動作します。 python subdir2/some_script.py
から/dir
を実行すると、予想される実行可能場所は/dir/../subdir2/some_executable
になります(別名/subdir2/some_executable
)。
スクリプト独自のディレクトリから特定の実行可能ファイルへの相対パスを確実に使用したい場合は、最初に__file__
グローバル変数のディレクトリ部分から絶対パスを作成するのが最良のオプションです。
#/usr/bin/env python
from subprocess import Popen, PIPE
from os.path import abspath, dirname, join
path = abspath(join(dirname(__file__), '../subdir1/some_executable'))
spam, eggs = Popen(path, stdout=PIPE, stderr=PIPE).communicate()
Pythonpathは、pythonインタープリターが実行されるパスから設定されます。したがって、例の2番目のケースでは、パスは/ dir/subdir2ではなく/ dirに設定されます。エラー。