python os.environ, os.putenv, /usr/bin/env

22

我想确保os.system('env')不包含在~/.bashrc中导出为export myname=csj的特定变量myname

因此,我编写了以下Python代码:

import os

def print_all():
    print "os.environ['myname']=%s" % os.environ.get('myname')
    print "os.getenv('myname')=%s" % os.getenv('myname')
    os.system('env | grep myname')
    print

def delete_myname():
    if 'myname' in os.environ: os.environ.pop('myname')
    if os.getenv('myname'): os.unsetenv('myname')

print_all()

os.putenv('myname', 'csj2')
print "---------------------"
delete_myname()
print_all()

os.putenv('myname', 'csj3')
print "---------------------"
delete_myname()
print_all()

我认为检查os.environ['myname']os.getenv('myname'), 如果存在则删除它们,可以确保os.system('env | grep myname')不会获取任何结果。

然而,实际结果是:

os.environ['myname']=csj
os.getenv('myname')=csj
myname=csj

---------------------
os.environ['myname']=None
os.getenv('myname')=None

---------------------
os.environ['myname']=None
os.getenv('myname')=None
myname=csj3

我不明白为什么在os.system('env | grep myname')中我仍然得到csj3


看起来发生了某种竞争条件。你是否一直得到相同的结果?如果添加第四轮,myname=csj3 是否会持续存在,还是只有第四轮中的 myname=csj4 - chepner
它总是得到相同的结果。实际上,在我的真实Python脚本中,第二个putenv()之间有很多东西/代码,让我感到困惑。现在我在第二个putenv()之前放了一个time.sleep(1),并使用while [ 1 ]; do python env.py ; sleep 1; done来执行脚本,总是得到相同的结果。 - CSJ
如果我删除一行代码 if 'myname' in os.environ: os.environ.pop('myname'),奇迹般地,os.system('env | grep myname') 没有输出任何内容,问题似乎得到解决。虽然我还不知道为什么... - CSJ
2个回答

30

根据文档

注意: 直接调用putenv()不会改变os.environ,因此最好修改os.environ。

对于unsetenv,有一个类似的警告:

但是,调用unsetenv()不会更新os.environ,因此最好删除os.environ中的项目。

getenv只是从os.environ返回值,因为它的实现显示,在使用它时,当您从Python中查找它时,您会进入似乎未设置该值的状态,而实际上在真实环境中设置了。我现在能想到的唯一方法是使用ctypes调用c getenv函数...

如果我修改您的代码来使用os.environ而不是调用putenv/unsetenv,则一切都按预期工作:

import os

def print_all():
    print "os.environ['myname']=%s" % (os.environ['myname'] if 'myname' in os.environ else "None")
    os.system('env | grep myname')
    print

def delete_myname():
    if 'myname' in os.environ: os.environ.pop('myname')

print_all()

os.environ['myname'] = 'csj2'
print "---------------------"
print_all()
delete_myname()
print_all()

os.environ['myname'] = 'csj3'
print "---------------------"
print_all()
delete_myname()
print_all()

输出:

$ myname=somevalue python2 test.py 
os.environ['myname']=somevalue
myname=somevalue

---------------------
os.environ['myname']=csj2
myname=csj2

os.environ['myname']=None

---------------------
os.environ['myname']=csj3
myname=csj3

os.environ['myname']=None

是的,我认为只使用os.environ可以确保/usr/bin/env没有该变量...但是因为其他团队的脚本使用putenv()来执行某些操作,而我调用了他们的脚本。我没有很好的理由说服他们改变他们的代码。我只是想尝试自己删除它。 - CSJ
2
向他们展示有关putenv/unsetenv的文档中的注释,以及getenv只返回os.environ中的内容。这应该能够说服他们。 - mata

0
一个好的做法可能是:
  • 删除myname环境变量(如果存在)
  • 运行你的函数
  • 在函数完成时恢复myname环境变量。

你可以通过类似于这个问题中描述的modified_environ上下文管理器轻松实现这一点。

with modified_environ('myname'):
    call_my_function()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接