CSJ
CSJ

Reputation: 2957

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

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')?

Upvotes: 25

Views: 54791

Answers (2)

mata
mata

Reputation: 69062

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 warning:

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 its 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 actually 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 C types...

If i modify your code to use os.environ instead 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

Upvotes: 32

Laurent LAPORTE
Laurent LAPORTE

Reputation: 22992

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

Upvotes: 0

Related Questions