【问题标题】:Start new subprocess with 'default' environment variables使用“默认”环境变量启动新子进程
【发布时间】:2014-05-19 00:35:35
【问题描述】:

我正在编写一个构建脚本来解析依赖的共享库(及其共享库等)。这些共享库不存在于普通的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,但构建脚本是跨平台的。

编辑:

跨平台约束似乎过于严格。现在可以考虑相同概念的不同实现。

例如,使用来自this 答案的代码,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 需要一种一致的方法。

【问题讨论】:

    标签: python environment-variables


    【解决方案1】:

    使用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)
    

    documentation 声明将使用提供的环境而不是从父级继承它:

    如果env不是None,它必须是定义环境的映射 新流程的变量;这些被使用而不是继承 当前进程的环境,这是默认行为。

    【讨论】:

    • python 构建脚本不会更改PATH 变量,因为还有其他非python 工具需要修改PATH。所以PATH的变化必须发生在加载脚本中。
    • 我编辑了我的答案以反映我认为您正在尝试做的事情,但我真的不确定我是否完全理解了这个问题。
    • 啊等等,加载器脚本不是用 Python 编写的吗?难道你不能让加载器脚本在调用 Python 脚本之前将默认路径保存到环境变量吗?
    • 对于任何混淆,我深表歉意。加载程序脚本是一个.bat 文件并且必须保持不变。我编辑了这个问题。您是否知道一种向操作系统“发出信号”以启动一个不是 Python 子进程的新进程的方法?
    • python 脚本是可移植的,但加载器脚本是特定于平台的。我不想将构建脚本中的任何引用放入备份 PATH。
    【解决方案2】:

    PATH 的“默认”值是什么意思?登录时它的价值?一些系统范围的默认值?加载程序脚本在进行更改之前开始使用的值?

    最简单的方法是用您自己的一个将 PATH 的当前值保存在其他环境变量(如 OLD_PATH)中的加载器脚本(如果您真的无法更改它)包装。然后你可以使用类似的东西:

    os.spawnle( ... , {'PATH' : os.environ['OLD_PATH']})
    

    或者您可以生成一个 shell 作为登录或至少交互式 shell,并在调用 python 之前让它获取用户的 .bashrc(或其他启动)。

    ** update ** for windows,并假设您只想获取 PATH:

    生成 CMD.EXE,让它执行命令 'echo %PATH%'

    【讨论】:

    • 此实例中的默认值被认为是加载程序脚本之前的环境。我不想将环境变量传递给子进程;我正在寻找返回默认环境的子进程。这是在 Windows 上,尽管构建脚本是跨平台的。
    • 我看到你希望生成的进程告诉你它的环境是什么。那么我的答案的第二部分出现了:生成一个正在运行 CMD.EXE(windows)或 bash(linux)的进程,并让它告诉你它的 PATH 是什么。更新这些细节的答案。
    • 我想过。有没有办法向操作系统发出“信号”以启动一个新进程(但不是当前 Python 进程的子进程)?
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2013-04-17
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    相关资源
    最近更新 更多