Why can't environmental variables set in python persist?

You can't do it from python, but some clever bash tricks can do something similar. The basic reasoning is this: environment variables exist in a per-process memory space. When a new process is created with fork() it inherits its parent's environment variables. When you set an environment variable in your shell (e.g. bash) like this:

export VAR="foo"

What you're doing is telling bash to set the variable VAR in its process space to "foo". When you run a program, bash uses fork() and then exec() to run the program, so anything you run from bash inherits the bash environment variables.

Now, suppose you want to create a bash command that sets some environment variable DATA with content from a file in your current directory called ".data". First, you need to have a command to get the data out of the file:

cat .data

That prints the data. Now, we want to create a bash command to set that data in an environment variable:

export DATA=`cat .data`

That command takes the contents of .data and puts it in the environment variable DATA. Now, if you put that inside an alias command, you have a bash command that sets your environment variable:

alias set-data="export DATA=`cat .data`"

You can put that alias command inside the .bashrc or .bash_profile files in your home directory to have that command available in any new bash shell you start.


One workaround is to output export commands, and have the parent shell evaluate this..

thescript.py:

import pipes
import random
r = random.randint(1,100)
print("export BLAHBLAH=%s" % (pipes.quote(str(r))))

..and the bash alias (the same can be done in most shells.. even tcsh!):

alias setblahblahenv="eval $(python thescript.py)"

Usage:

$ echo $BLAHBLAH

$ setblahblahenv
$ echo $BLAHBLAH
72

You can output any arbitrary shell code, including multiple commands like:

export BLAHBLAH=23 SECONDENVVAR='something else' && echo 'everything worked'

Just remember to be careful about escaping any dynamically created output (the pipes.quote module is good for this)