Python's access to environment variables does not accurately reflect the operating system's view of the processes environment.
Python对环境变量的访问不能准确反映操作系统对进程环境的看法。
os.getenv and os.environ do not function as expected in particular cases.
在特定情况下,os.getenv和os.environ没有按预期运行。
Is there a way to properly get the running process' environment?
有没有办法正确地获得正在运行的进程环境?
To demonstrate what I mean, take the two roughly equivalent programs (the first in C, the other in python):
为了证明我的意思,取两个大致相同的程序(第一个在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)
Now, if we run the C program and attach to the running process with gdb and forcibly change the environment under the hood by doing something like this:
现在,如果我们运行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"
then the aforementioned C program will start spewing out "my value" once every 5 seconds. The aforementioned python program, however, will not.
然后前面提到的C程序将开始每5秒喷出一次“我的价值”。然而,前面提到的python程序不会。
Is there a way to get the python program to function like the C program in this case?
有没有办法让python程序在这种情况下像C程序一样运行?
(Yes, I realize this is a very obscure and potentially damaging action to perform on a running process)
(是的,我意识到这是一个非常模糊且可能在运行过程中执行的潜在破坏性操作)
Also, I'm currently using python 2.4, this may have been fixed in a later version of python.
此外,我目前正在使用python 2.4,这可能已在更高版本的python中修复。
5 个解决方案
#1
14
That's a very good question.
这是一个非常好的问题。
It turns out that the os
module initializes os.environ
to the value of posix
.environ
, which is set on interpreter start up. In other words, the standard library does not appear to provide access to the getenv function.
事实证明,os模块将os.environ初始化为posix.environ的值,该值在解释器启动时设置。换句话说,标准库似乎不提供对getenv函数的访问。
That is a case where it would probably be safe to use ctypes on unix. Since you would be calling an ultra-standard libc function.
这种情况下,在unix上使用ctypes可能是安全的。因为您将调用超标准的libc函数。
#2
11
You can use ctypes
to do this pretty simply:
您可以使用ctypes非常简单地执行此操作:
>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'
#3
4
Another possibility is to use pdb, or some other python debugger instead, and change os.environ at the python level, rather than the C level. Here's a small recipe I posted to interrupt a running python process and provide access to a python console on receiving a signal. Alternatively, just stick a pdb.set_trace() at some point in your code you want to interrupt. In either case, just run the statement "import os; os.environ['SOME_VARIABLE']='my_value'
" and you should be updated as far as python is concerned.
另一种可能性是使用pdb或其他一些python调试器,并在python级别而不是C级别更改os.environ。这是我发布的一个小方法,用于中断正在运行的python进程,并在接收信号时提供对python控制台的访问。或者,只需在要中断的代码中的某个位置粘贴pdb.set_trace()。在任何一种情况下,只需运行语句“import os; os.environ ['SOME_VARIABLE'] ='my_value'”,就python而言你应该更新。
I'm not sure if this will also update the C environment with setenv, so if you have C modules using getenv directly you may have to do some more work to keep this in sync.
我不确定这是否也会用setenv更新C环境,所以如果你有直接使用getenv的C模块,你可能需要做更多的工作来保持同步。
#4
3
I don't believe many programs EVER expect to have their environment externally modified, so loading a copy of the passed environment at startup is equivalent. You have simply stumbled on an implementation choice.
我不相信很多程序都希望外部修改它们的环境,因此在启动时加载传递环境的副本是等效的。您只是偶然发现了一个实现选择。
If you are seeing all the set-at-startup values and putenv/setenv from within your program works, I don't think there's anything to be concerned about. There are far cleaner ways to pass updated information to running executables.
如果您在程序中看到所有启动设置值和putenv / setenv,我认为没有什么值得关注的。有更简洁的方法将更新的信息传递给正在运行的可执行文件。
#5
1
Looking at the Python source code (2.4.5):
看一下Python源代码(2.4.5):
-
Modules/posixmodule.c gets the environ in convertenviron() which gets run at startup (see INITFUNC) and stores the environment in a platform-specific module (nt, os2, or posix)
modules / posixmodule.c获取convertenviron()中的environ,它在启动时运行(参见INITFUNC)并将环境存储在特定于平台的模块(nt,os2或posix)中
-
Lib/os.py looks at sys.builtin_module_names, and imports all symbols from either posix, nt, or os2
Lib / os.py查看sys.builtin_module_names,并从posix,nt或os2导入所有符号
So yes, it gets decided at startup. os.environ is not going to be helpful here.
所以是的,它会在启动时决定。 os.environ在这里不会有用。
If you really want to do this, then the most obvious approach that comes to mind is to create your own custom C-based python module, with a getenv that always invokes the system call.
如果你真的想这样做,那么最明显的方法是创建你自己的自定义基于C的python模块,getenv总是调用系统调用。
#1
14
That's a very good question.
这是一个非常好的问题。
It turns out that the os
module initializes os.environ
to the value of posix
.environ
, which is set on interpreter start up. In other words, the standard library does not appear to provide access to the getenv function.
事实证明,os模块将os.environ初始化为posix.environ的值,该值在解释器启动时设置。换句话说,标准库似乎不提供对getenv函数的访问。
That is a case where it would probably be safe to use ctypes on unix. Since you would be calling an ultra-standard libc function.
这种情况下,在unix上使用ctypes可能是安全的。因为您将调用超标准的libc函数。
#2
11
You can use ctypes
to do this pretty simply:
您可以使用ctypes非常简单地执行此操作:
>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'
#3
4
Another possibility is to use pdb, or some other python debugger instead, and change os.environ at the python level, rather than the C level. Here's a small recipe I posted to interrupt a running python process and provide access to a python console on receiving a signal. Alternatively, just stick a pdb.set_trace() at some point in your code you want to interrupt. In either case, just run the statement "import os; os.environ['SOME_VARIABLE']='my_value'
" and you should be updated as far as python is concerned.
另一种可能性是使用pdb或其他一些python调试器,并在python级别而不是C级别更改os.environ。这是我发布的一个小方法,用于中断正在运行的python进程,并在接收信号时提供对python控制台的访问。或者,只需在要中断的代码中的某个位置粘贴pdb.set_trace()。在任何一种情况下,只需运行语句“import os; os.environ ['SOME_VARIABLE'] ='my_value'”,就python而言你应该更新。
I'm not sure if this will also update the C environment with setenv, so if you have C modules using getenv directly you may have to do some more work to keep this in sync.
我不确定这是否也会用setenv更新C环境,所以如果你有直接使用getenv的C模块,你可能需要做更多的工作来保持同步。
#4
3
I don't believe many programs EVER expect to have their environment externally modified, so loading a copy of the passed environment at startup is equivalent. You have simply stumbled on an implementation choice.
我不相信很多程序都希望外部修改它们的环境,因此在启动时加载传递环境的副本是等效的。您只是偶然发现了一个实现选择。
If you are seeing all the set-at-startup values and putenv/setenv from within your program works, I don't think there's anything to be concerned about. There are far cleaner ways to pass updated information to running executables.
如果您在程序中看到所有启动设置值和putenv / setenv,我认为没有什么值得关注的。有更简洁的方法将更新的信息传递给正在运行的可执行文件。
#5
1
Looking at the Python source code (2.4.5):
看一下Python源代码(2.4.5):
-
Modules/posixmodule.c gets the environ in convertenviron() which gets run at startup (see INITFUNC) and stores the environment in a platform-specific module (nt, os2, or posix)
modules / posixmodule.c获取convertenviron()中的environ,它在启动时运行(参见INITFUNC)并将环境存储在特定于平台的模块(nt,os2或posix)中
-
Lib/os.py looks at sys.builtin_module_names, and imports all symbols from either posix, nt, or os2
Lib / os.py查看sys.builtin_module_names,并从posix,nt或os2导入所有符号
So yes, it gets decided at startup. os.environ is not going to be helpful here.
所以是的,它会在启动时决定。 os.environ在这里不会有用。
If you really want to do this, then the most obvious approach that comes to mind is to create your own custom C-based python module, with a getenv that always invokes the system call.
如果你真的想这样做,那么最明显的方法是创建你自己的自定义基于C的python模块,getenv总是调用系统调用。