8
subprocess.run('export FOO=BAR', shell=True)

This simply doesn't work, and I have no idea why.

All I am trying to do I set an environment variable from my python (3.5.1) script, and when I run the above line, nothing happens. No errors are raised, and when I check the environment variable myself, it has not been set.

Other shell commands with subprocess.run() do work, such as ls and pwd, but not export.

.run() was added in Python 3.5 (in case you didn't recognise it), but I have also tried the above line with .call() and .Popen(), with no change in results.

I am aware that I can set environment variables in python with os.environ['FOO'] = "BAR", but I will be using shell commands a lot in my project, and I expect that I will need to string multiple commands together, which will make using export easier than os.environ.

My project will run on Linux, which is what my machine is running on.

99lives
  • 798
  • 1
  • 8
  • 17
  • think: each `subprocess.run(shell=True)` starts a new shell. Open two terminals and type `export FOO=BAR` in one terminal and `echo $FOO` in another (the second terminal that runs a separate shell won't see the new `$FOO` value). It is the same reason why `cd` is a shell builtin (because it changes the working directory of the current process and if it were a separate program then `cd` would had to change the environment of the parent process—that can't be done (normally)). See [How do I set the working directory of the parent process?](http://stackoverflow.com/q/2375003/4279) – jfs May 18 '16 at 23:27

1 Answers1

12

It works fine; however, the variable setting only exists in the subprocess. You cannot affect the environment of the local process from a child.

os.environ is the correct solution, as it changes the environment of the local process, and those changes will be inherited by any process started with subprocess.run.

You can also use the env argument to run:

subprocess.run(["cmdname", "arg1", "arg number 2"], env=dict(FOO='BAR', **os.environ))

This runs the command in a modified environment that includes FOO=BAR without modifying the current environment.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Ahhh. So is my only option to use `os.environ`, or is there something else I can do? – 99lives May 17 '16 at 11:48
  • I'm not sure why you are objecting to using `os.environ` so much. That *is* the Python equivalent of using the shell's builtin `export` command in a shell script. – chepner May 17 '16 at 11:55
  • Like I said, I expect to be stringing multiple commands together; I believe it would be easier to add `export` to a list of commands I will need to execute, rather than do so in a separate python function. That's fine though, I can figure something out. Thanks for your answer, it explained why it wasn't working as I expected :) – 99lives May 17 '16 at 12:01
  • you could use `dict(os.environ, FOO='BAR')` instead of `dict(FOO='BAR', **os.environ)` – jfs May 18 '16 at 23:20