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 中修复。

有帮助吗?

解决方案

这是一个非常好的问题。

事实证明 os 模块将 os.environ 初始化为 posix .environ ,在解释器启动时设置。换句话说,标准库似乎无法访问 getenv 功能。

在unix上使用 ctypes 可能是安全的。因为您将调用超标准的libc函数。

其他提示

你可以使用 ctypes 来做到这一点:

>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'

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

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

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

如果您看到所有启动设置值和程序中的putenv / setenv有效,我认为没有什么值得关注的。有更简洁的方法可以将更新的信息传递给正在运行的可执行文件。

查看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。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top