14

Python 对环境变量的访问并不能准确地反映操作系统对进程环境的看法。

os.getenv 和 os.environ 在特定情况下无法按预期运行。

有没有办法正确获取正在运行的进程的环境?


为了说明我的意思,请使用两个大致等效的程序(第一个在 C 中,另一个在 python 中):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]){
    char *env;
    for(;;){
        env = getenv("SOME_VARIABLE");
        if(env)
            puts(env);
        sleep(5);
    }
}

import os
import time
while True:
    env = os.getenv("SOME_VARIABLE")
    if env is not None:
        print env
    time.sleep(5)

现在,如果我们运行 C 程序并使用 gdb 附加到正在运行的进程,并通过执行以下操作强制更改引擎盖下的环境:

(gdb) print setenv("SOME_VARIABLE", "my value", 1)
[Switching to Thread -1208600896 (LWP 16163)]
$1 = 0
(gdb) print (char *)getenv("SOME_VARIABLE")
$2 = 0x8293126 "my value"

那么前面提到的 C 程序将开始每 5 秒喷出一次“我的价值”。但是,前面提到的 python 程序不会。

在这种情况下,有没有办法让 python 程序像 C 程序一样运行?

(是的,我意识到这是对正在运行的进程执行的非常模糊且可能具有破坏性的操作)

另外,我目前使用的是 python 2.4,这可能已在更高版本的 python 中修复。

4

5 回答 5

14

这是一个非常好的问题。

事实证明,os模块初始化os.environ为 的值,该值是在解释器启动时设置的。换句话说,标准库似乎不提供对getenv函数的访问。posix.environ

在这种情况下,在 unix上使用ctypes可能是安全的。因为你会调用一个超标准的 libc 函数。

于 2008-10-24T22:28:38.507 回答
11

你可以ctypes很简单地做到这一点:

>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'
于 2008-10-28T03:38:23.317 回答
4

另一种可能性是使用 pdb 或其他一些 python 调试器,并在 python 级别而不是 C 级别更改 os.environ。 这是我发布的一个小秘诀,用于中断正在运行的 python 进程并在接收信号时提供对 python 控制台的访问。或者,只需在要中断的代码中的某个位置粘贴一个 pdb.set_trace() 即可。在任何一种情况下,只需运行语句“ import os; os.environ['SOME_VARIABLE']='my_value'”,就 python 而言,您应该进行更新。

我不确定这是否也会用 setenv 更新 C 环境,所以如果你有 C 模块直接使用 getenv,你可能需要做更多的工作来保持同步。

于 2008-10-25T23:50:56.333 回答
3

我不相信许多程序会期望对其环境进行外部修改,因此在启动时加载传递的环境的副本是等效的。您只是偶然发现了一个实现选择。

如果您在程序中看到所有的 set-at-startup 值和 putenv/setenv 工作,我认为没有什么可担心的。有更简洁的方法可以将更新的信息传递给正在运行的可执行文件。

于 2008-10-25T14:53:21.713 回答
1

查看 Python 源代码(2.4.5):

  • Modules/posixmodule.c 在 convertenviron() 中获取环境,该环境在启动时运行(参见 INITFUNC)并将环境存储在特定于平台的模块(nt、os2 或 posix)中

  • Lib/os.py 查看 sys.builtin_module_names,并从 posix、nt 或 os2 导入所有符号

所以是的,它是在启动时决定的。os.environ 在这里不会有帮助。

如果您真的想这样做,那么想到的最明显的方法是创建您自己的基于 C 的自定义 python 模块,并使用始终调用系统调用的 getenv。

于 2008-10-24T22:16:52.557 回答