python子进程Popen环境路径?

2024-07-01 07:11:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我对使用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')])

并验证在使用ipython以交互方式启动python时,或通过从命令行运行脚本时,PYTHONPATH是否成功出现在os.environ中。但是,subrocess.Popen仍然没有在那里搜索可执行文件。我想如果没有指定envkwarg,它应该继承父环境?接下来,我尝试显式地给出env,首先复制os.getenv,然后只给出env={'PATH': '/explicit/path/to/search/from'},它仍然找不到可执行文件。现在我被难住了。

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

/dir/subdir1/some_可执行文件
/目录/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


Tags: topathpy可执行文件osdirenvironscript
3条回答

(从评论中填写细节,单独作答)

首先,相对路径(包含斜线的路径)永远不会签入任何路径,无论您做什么。它们仅与当前工作目录相关。如果需要解析相对路径,则必须手动搜索该路径,或者将该路径修改为包含子目录,然后使用命令名,如下面的建议所示。

如果要相对于Python脚本的位置运行程序,请使用__file__,然后从中查找程序的绝对路径,然后使用Popen中的绝对路径。

其次,还有an issue in the Python bug tracker关于Python如何处理裸命令(没有斜杠)。基本上,在Unix/Mac上,Popen使用os.execvp调用时使用shell=False,这意味着它会像Python启动时那样查看PATH的值,任何更改都不会帮助您解决这个问题。另外,在具有shell=False的Windows上,它根本不关注路径,只会查找相对于当前工作目录的路径。

如果您只需要路径计算,而不想通过shell运行命令行,并且是在UNIX上,我建议您使用env,而不是shell=True,如Popen(['/usr/bin/env', 'progtorun', other, args], ...)。这允许您将不同的路径传递给env进程,该进程将使用它来查找程序。它还避免了shell元字符的问题和通过shell传递参数的潜在安全问题。显然,在Windows(几乎是唯一没有/usr/bin/env的平台)上,您需要做一些不同的事情。

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

PATH是一个环境变量,它告诉OS shell在哪里搜索可执行文件。

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

由于底层实现的不同,subprocess.Popen将只在非Windows系统上默认搜索路径(Windows有一些它总是搜索的系统目录,但这与PATH处理不同)。扫描路径的唯一可靠跨平台方法是将shell=True传递给子进程调用,但这有其自身的问题(如^{} documentation中所述)

但是,您的主要问题似乎是,您将路径片段传递给Popen,而不是简单的文件名。一旦有了目录分隔符,就要禁用PATH搜索,即使是在非Windows平台上(例如,请参阅Linux文档中的exec family of functions)。

Popen中的相对路径相对于当前工作目录,而不是系统路径的元素。如果从/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()

相关问题 更多 >

    热门问题