pythonsubprocessPopen环境PATH?

我很困惑如何使用Popen()search可执行文件。 它的作品,如果给予subprocess的绝对path,但我试图使用相对path。 我发现,如果我设置环境variablesPYTHONPATH,那么我可以从该path中获取导入的模块,并且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')]) 

并通过交互方式,使用ipython或通过从命令行运行脚本来validation启动python时,PYTHONPATH成功显示在os.environ 。 但是, subrocess.Popen 仍然不在那里search可执行文件。 如果没有指定env kwarg,我认为它应该inheritance父母的环境? 接下来,我尝试给env明确,首先通过复制os.getenv ,其次是通过给env={'PATH': '/explicit/path/to/search/from'} ,它仍然没有find可执行文件。 现在我很难过

希望有个例子能更清楚地解释我的问题:

/目录/ 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'] ,那么subprocess会抛出OSError: [Errno 2] No such file or directory

(填写评论的细节作出单独的答案)

首先,无论你做什么,相对path(包含斜杠的path)都不会被PATH检查。 它们仅与当前工作目录相关 。 如果您需要parsing相对path,则必须手动searchPATH,或者将PATH包含在子目录中,然后按照我的build议使用命令名称。

如果你想运行一个相对于Python脚本的位置的程序,使用__file__并从那里去find程序的绝对path,然后在Popen使用绝对path。

其次, Python错误跟踪器中有一个关于Python如何处理裸指令(无斜线)的问题。 基本上,在Unix / Mac上,当os.execvp使用shell=False调用时, os.execvp使用os.execvp ,这意味着它会像Python启动时那样查看PATH的值,并且没有任何改变的os.environ会帮助你修复这个问题。 另外,在shell=False Windows上,完全不关注PATH,只会查看当前工作目录。

如果你只是需要path评估,并不真的想通过shell运行你的命令行,并且在UNIX上,我build议使用env而不是shell=True ,如Popen(['/usr/bin/env', 'progtorun', other, args], ...) 。 这可以让你传递一个不同的PATH到env进程,用它来find程序。 它还避免了shell元字符的问题,以及通过shell传递参数的潜在安全问题。 显然,在Windows上(几乎没有/usr/bin/env ),你需要做一些不同的事情。

您似乎对PATHPYTHONPATH的性质有点困惑。

PATH是一个环境variables,告诉OS shell在哪里search可执行文件。

PYTHONPATH是一个环境variables,它告诉Python解释器在哪里search要导入的模块。 它与subprocess查找可执行文件无关。

由于底层实现的不同, subprocess.Popen将只在非Windows系统上默认searchpath(Windows有一些总是search的系统目录,但这不同于PATH处理)。 扫描path的唯一可靠的跨平台方法是将shell=True传递给subprocess调用,但它有自己的问题(详见Popen文档 )

然而,看来你的主要问题是你传递一个path片段到Popen而不是一个简单的文件名。 只要你有一个目录分隔符,即使在非Windows平台上,你也要禁用PATHsearch(例如,查看exec系列函数的Linux文档)。

subprocess.Popen中的相对path相对于当前工作目录而不是系统PATH的元素。 如果从/dir运行python subdir2/some_script.py ,则预期的可执行文件位置将是/dir/../subdir2/some_executable ,又名/subdir2/some_executable

如果你肯定喜欢使用从脚本自己的目录到特定的可执行文件的相对path,最好的select是首先从__file__全局variables的目录部分构build一个绝对path。

 #/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解释器的path。 所以,在你的例子的第二种情况下,path设置为/ dir而不是/ dir / subdir2这就是为什么你会得到一个错误。