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
),你需要做一些不同的事情。
您似乎对PATH
和PYTHONPATH
的性质有点困惑。
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平台上,你也要禁用PATH
search(例如,查看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这就是为什么你会得到一个错误。