22

I want to ensure os.system('env') not contain some specific variable myname which is export in ~/.bashrc as export myname=csj

Therefore, I wrote below python code:

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()

I think examine both os.environ['myname'] and os.getenv('myname') and then delete them if exist, can ensure os.system('env | grep myname') get nothing.

However, the result is:

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

I don't understand why I still got csj3 on os.system('env | grep myname')?

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
CSJ
  • 2,709
  • 4
  • 24
  • 30
  • It looks like there is some sort of race condition occurring. Do you get the same results consistently? If you add a 4th round, does `myname=csj3` persist, or only `myname=csj4` in the 4th round? – chepner Jul 17 '13 at 16:50
  • it got the same result always. Actually in my real python script, there are many stuff/code between the second putenv(), very confuse me ..Now I put a time.sleep(1) before 2nd putenv(), and `while [ 1 ]; do python env.py ; sleep 1; done` to execute the script, got the same result always. – CSJ Jul 17 '13 at 16:54
  • if I delete one line `if 'myname' in os.environ: os.environ.pop('myname')`, amazingly, I got nothing on `os.system('env | grep myname')` and seems solve the problem. Although I still don't know why... – CSJ Jul 17 '13 at 19:07

2 Answers2

30

From the docs:

Note: Calling putenv() directly does not change os.environ, so it’s better to modify os.environ.

For unsetenv there is a similar warining:

however, calls to unsetenv() don’t update os.environ, so it is actually preferable to delete items of os.environ.

getenv just returns the value from os.environ, as it's implementation shows, so by using it you get into a state where it seems the value isn't set when you look it up from python, while it acutally is in the real environment. The only way to get it now I can think of would be to call the c getenv function using ctypes...

If i modify your code to use os.environ isnstead of calling putenv/unsetenv everything works as expected:

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()

output:

$ 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
mata
  • 67,110
  • 10
  • 163
  • 162
  • Yes, I think if only use os.environ can ensure /usr/bin/env not have the variable... but cause other team's script use putenv() to do something, and I call their script. I don't have very good reason to convince them to change their code. I just want try to delete it myself. – CSJ Jul 17 '13 at 17:09
  • 2
    Show them the the note in the documentation for putenv/unsetenv, and that getenv just returns whatever is in `os.environ`. That should convince them. – mata Jul 17 '13 at 17:12
0

A good practice could be:

  • delete the myname environment variable (if it exists),
  • run your function
  • restore the myname environment variable at function completion.

Yu can do that easily with something like the modified_environ context manager describe in this question.

with modified_environ('myname'):
    call_my_function()
Community
  • 1
  • 1
Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103