2008-10-24 57 views
12

Python对环境变量的访问不能准确反映操作系统对进程环境的看法。Linux上的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,这可能被固定在蟒蛇的更高版本。

+0

对于它的价值,这并不令人意外:为os模块库参考突出的问题。 – bobince 2008-10-24 22:35:50

回答

14

这是一个非常好的问题。

事实证明,所述os模块初始化os.environ到的posix.environ的值,其被设定在解释器启动。换句话说,标准库似乎不提供对getenv函数的访问。

这是一个在unix上使用ctypes可能是安全的情况。既然你会叫一个超标准的libc函数。

1

望着Python源代码(2.4.5):

  • 模块/ posixmodule.c获取convertenviron的ENVIRON(),它被启动时运行(见INITFUNC),并在存储环境相关平台模块(NT,OS2或POSIX)

  • 库/ os.py看着sys.builtin_module_names,进口全部来自任何POSIX符号,NT或OS2

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

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

+0

或者我可以使用ctypes模块,但现在只是破坏了它的乐趣,不是吗? – Sufian 2008-10-24 22:18:06

3

我不相信有很多的程序也希望有自己的环境外部修改,在启动时加载所以传递环境的副本等同。你只是偶然发现了一个实现选择。

如果从内部程序的工作原理看到所有的设置在-启动值和运行putenv/SETENV,我不认为有什么可担心。有更简洁的方法将更新的信息传递给正在运行的可执行文件。

4

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

我不知道这是否也将更新C环境SETENV,因此,如果您使用的getenv拥有的C模块直接您可能需要做更多的工作来保持这种同步。

10

您可以使用​​做到这一点很简单:

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