python子进程Popen环境PATH?
我对使用Popen()
时subprocess
Popen()
如何搜索可执行文件感到困惑。 它的作品,如果给予子进程的绝对路径,但我试图使用相对路径。 我发现如果我设置了环境变量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')])
并通过交互方式,使用ipython或通过从命令行运行脚本启动python时确认,PYTHONPATH已成功显示在os.environ
。 但是,子subrocess.Popen
仍然不会在那里搜索可执行文件。 如果没有指定env
kwarg,我认为它应该继承父母环境? 接下来,我尝试给env
明确,首先通过复制os.getenv
,其次通过给env={'PATH': '/explicit/path/to/search/from'}
,它仍然没有找到可执行文件。 现在我很难过。
希望一个例子能够更清楚地解释我的问题:
/目录/ 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中检查。 它们仅与当前工作目录相关。 如果需要解析相对路径,则必须手动搜索PATH,或者将PATH包含到子目录中,然后按照我的建议使用命令名称。
如果你想运行一个相对于Python脚本位置的程序,使用__file__
并从那里去找到程序的绝对路径,然后在Popen
使用绝对路径。
其次,Python bug跟踪器中存在一个关于Python如何处理裸指令(无斜线)的问题。 基本上,在UNIX / Mac Popen
使用os.execvp
时调用shell=False
,这意味着它着眼于价值PATH
,因为它是在Python的推出,并没有改变量os.environ
将帮助你解决这个问题。 另外,在shell=False
Windows上,根本不关注PATH,只会查看当前工作目录。
如果您只需要路径评估,并且不想通过shell运行命令行,并且在UNIX上,我建议使用env
而不是shell=True
,如在Popen(['/usr/bin/env', 'progtorun', other, args], ...)
。 这可以让您将不同的PATH传递给env
进程,该进程将使用它来查找程序。 它还避免了shell元字符的问题以及通过shell传递参数的潜在安全问题。 显然,在Windows上(几乎没有/usr/bin/env
的唯一平台),你需要做一些不同的事情。
您似乎对PATH
和PYTHONPATH
的性质有点困惑。
PATH
是一个环境变量,它告诉OS shell在哪里搜索可执行文件。
PYTHONPATH
是一个环境变量,它告诉Python解释器在哪里搜索要导入的模块。 它与subprocess
查找可执行文件无关。
由于底层实现的不同, subprocess.Popen
将只在非Windows系统上默认搜索路径(Windows有一些系统目录,它总是搜索,但与PATH
处理不同)。 扫描路径的唯一可靠的跨平台方法是将shell=True
传递给子进程调用,但它有自己的问题(详见Popen
文档)
但是,看起来你的主要问题是你正在传递一个路径片段给Popen
而不是一个简单的文件名。 只要你有一个目录分隔符,即使在非Windows平台上,你也要禁用PATH
搜索(例如,参见exec函数家族的Linux文档)。
subprocess.Popen中的相对路径相对于当前工作目录而不是系统PATH的元素。 如果从/dir
运行python subdir2/some_script.py
,则预期的可执行位置将为/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()
链接地址: http://www.djcxy.com/p/77133.html
上一篇: python subprocess Popen environment PATH?
下一篇: capturing stderr of subprocesses with their shell stdout alive