使用“默认”环境变量启动新子进程
我正在写一个构建脚本,用来解决依赖的共享库(还有它们的共享库等等)。这些共享库不在正常的 PATH
环境变量里。
为了让构建过程顺利进行(让编译器能找到这些库),我修改了 PATH
,把这些库的目录加上去了。
构建过程是这样的:
加载脚本(修改 PATH
) -> 基于Python的构建脚本 -> 配置 -> 构建 -> 解决依赖 -> 安装。
这个Python实例从它的父shell那里继承了修改过的 PATH
变量。
在Python里面,我想获取默认的 PATH
(不是从父shell继承来的那个)。
我的想法:
获取“默认” PATH
变量的想法是以某种方式“通知”操作系统启动一个新进程(运行一个打印 PATH
的脚本),但这个进程不是当前Python进程的子进程(这样就不会继承它修改过的环境变量)。
尝试的实现:
import os
import sys
print os.environ["PATH"]
print "---"
os.spawnl(os.P_WAIT, sys.executable, "python", "-c \"import os;print(os.environ['PATH']);\"")
os.spawn
似乎使用的是和调用它的Python进程相同的环境变量。我也尝试了 subprocess.POpen
,但没有成功。
这个方法能实现吗?如果不能,有什么替代的方法(考虑到加载脚本和整体过程不能改变)?
我现在使用的是Windows,但这个构建脚本要跨平台。
编辑:
跨平台的限制似乎太严格了。现在可以考虑同一概念的不同实现。
举个例子,使用来自 这个回答的代码,可以通过Windows注册表获取“默认”的系统 PATH
变量。
try:
import _winreg as winreg
except ImportError:
try:
import winreg
except ImportError:
winreg = None
def env_keys(user=True):
if user:
root = winreg.HKEY_CURRENT_USER
subkey = "Environment"
else:
root = winreg.HKEY_LOCAL_MACHINE
subkey = r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
return root, subkey
def get_env(name, user=True):
root, subkey = env_keys(user)
key = winreg.OpenKey(root, subkey, 0, winreg.KEY_READ)
try:
value, _ = winreg.QueryValueEx(key, name)
except WindowsError:
return ""
value = winreg.ExpandEnvironmentStrings(value)
return value
print get_env("PATH", False)
需要为 *nix 系统找到一个一致的方法。
2 个回答
你说的“PATH的默认值”到底是什么意思呢?是你登录时的值吗?还是某种系统范围内的默认值?又或者是加载脚本开始时的值,在它做出更改之前的值?
最简单的方法就是,如果你真的不能修改加载脚本,可以用你自己的脚本把当前的PATH值保存到另一个环境变量,比如叫OLD_PATH。然后你可以用类似这样的代码:
os.spawnle( ... , {'PATH' : os.environ['OLD_PATH']})
或者你可以启动一个登录的shell,或者至少是一个交互式的shell,让它先加载用户的.bashrc(或者其他启动文件),然后再执行python。
** 更新 ** 如果是在Windows上,并且你只是想获取PATH值的话:
启动CMD.EXE,执行命令'echo %PATH%'。
使用 subprocess.Popen
,你可以为子进程提供一个环境变量:
default_path = os.environ['PATH'] # save the default path before changing it
os.environ['PATH'] = # whatever you want
child_env = os.environ.copy()
child_env['PATH'] = default_path
# change env
subprocess.Popen(..., env=child_env)
根据文档的说明,提供的环境变量会被用来替代从父进程继承的环境变量:
如果 env 不是 None,它必须是一个映射,定义了新进程的环境变量;这些变量会被用来替代当前进程的环境变量,而后者是默认的行为。