views:

2368

answers:

5

I was hoping to write a python script to create some appropriate environmental variables by running the script in whatever directory I'll be executing some simulation code, and I've read that I can't write a script to make these env vars persist in the mac os terminal. So two things:

Is this true?

and

It seems like it would be a useful things to do; why isn't it possible in general?

+1  A: 

It's not generally possible. The new process created for python cannot affect its parent process' environment. Neither can the parent affect the child, but the parent gets to setup the child's environment as part of new process creation.

Perhaps you can set them in .bashrc, .profile or the equivalent "runs on login" or "runs on every new terminal session" script in MacOS.

You can also have python start the simulation program with the desired environment. (use the env parameter to subprocess.Popen (http://docs.python.org/library/subprocess.html) )

import subprocess, os
os.chdir('/home/you/desired/directory')
subprocess.Popen(['desired_program_cmd', 'args', ...], env=dict(SOMEVAR='a_value') )

Or you could have python write out a shell script like this to a file with a .sh extension:

export SOMEVAR=a_value
cd /home/you/desired/directory
./desired_program_cmd

and then chmod +x it and run it from anywhere.

Joe Koberg
The simulation software I'm using requires a certain environmental variable to be set **by hand** for any directory you want to do an analysis in. I see this as a terrible approach and thought to fix it, or at least automate it, with python.
vgm64
+1  A: 

If you set environment variables within a python script (or any other script or program), it won't affect the parent shell.

Edit clarification: So the answer to your question is yes, it is true. You can however export from within a shell script and source it by using the dot invocation

in fooexport.sh

export FOO="bar"

at the command prompt

$ . ./fooexport.sh
$ echo $FOO
bar
Stefano Borini
So what about writing an alias that 1) runs a python script in cwd that creates a shell script with environmental variables i need based on the cwd and 2) invokes that script as you've written?
vgm64
Stefano, I checked out the Papers application mentioned on ForTheScience.org. I'm glad you decided to answer my question! If I obtain the student discount it will definitely worth the price, I suspect, so thank you.
vgm64
oh yes, the alias as you said will work, because it is invoked your current shell. That's definitely a solution to your issue.
Stefano Borini
+8  A: 

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.

Benson
+2  A: 

What I like to do is use /usr/bin/env in a shell script to "wrap" my command line when I find myself in similar situations:

#!/bin/bash

/usr/bin/env NAME1="VALUE1" NAME2="VALUE2" ${*}

So let's call this script "myappenv". I put it in my $HOME/bin directory which I have in my $PATH.

Now I can invoke any command using that environment by simply prepending "myappenv" as such:

myappenv dosometask -xyz

Other posted solutions work too, but this is my personal preference. One advantage is that the environment is transient, so if I'm working in the shell only the command I invoke is affected by the altered environment.

Modified version based on new comments

#!/bin/bash

/usr/bin/env G4WORKDIR=$PWD ${*}

You could wrap this all up in an alias too. I prefer the wrapper script approach since I tend to have other environment prep in there too, which makes it easier for me to maintain.

Joe Holloway
+1  A: 

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

thescript.py:

import random
r = random.randint(1,100)
print("export BLAHBLAH='%s'" % (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
dbr