web-dev-qa-db-ja.com

pythonサブプロセスPopen環境PATH?

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.Popenstillは、実行可能ファイルを検索しません。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/subdir2os.environ['PATH']にある場合、サブプロセスはOSError: [Errno 2] No such file or directoryをスローします。

52
wim

PATHPYTHONPATHの性質について少し混乱しているように見えます。

PATHは、実行可能ファイルを検索する場所をOSシェルに指示する環境変数です。

PYTHONPATHは、Pythonインタープリターにインポートするモジュールを検索する場所を指示する環境変数です。実行ファイルを見つけるsubprocessとは何の関係もありません。

基礎となる実装の違いにより、subprocess.Popenは、Windows以外のシステムでデフォルトでパスのみを検索します(Windowsには常に検索するシステムディレクトリがいくつかありますが、PATH処理とは異なります)。パスをスキャンする唯一の信頼できるクロスプラットフォームの方法は、Shell=Trueはサブプロセス呼び出しに対応していますが、独自の問題があります(詳細は Popenのドキュメント

ただし、主な問題は、単純なファイル名ではなくPopenにパスフラグメントを渡すことです。そこにディレクトリセパレーターがあるとすぐに、Windows以外のプラットフォームでもPATH検索を無効にします(たとえば、 execファミリー関数)についてはLinuxのドキュメントを参照してください )。

12
ncoghlan

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()
2
Jeremy Fishman

Pythonpathは、pythonインタープリターが実行されるパスから設定されます。したがって、例の2番目のケースでは、パスは/ dir/subdir2ではなく/ dirに設定されます。エラー。

0
c0da