28

In Linux When I invoke python from the shell it replicates its environment, and starts the python process. Therefore if I do something like the following:

import os
os.environ["FOO"] = "A_Value"

When the python process returns, FOO, assuming it was undefined originally, will still be undefined. Is there a way for the python process (or any child process) to modify the environment of its parent process?

I know you typically solve this problem using something like

source script_name.sh

But this conflicts with other requirements I have.

jww
  • 97,681
  • 90
  • 411
  • 885
grieve
  • 13,220
  • 10
  • 49
  • 61
  • See this related question: http://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables – Davide Nov 04 '08 at 22:20
  • Andrew from that thread answered: Via gdb: (gdb) attach process_id (gdb) call putenv ("env_var_name=env_var_value") (gdb) detach This is quite a nasty hack and should only be done in the context of a debugging scenario, of course. – grieve Nov 06 '08 at 15:39

4 Answers4

24

No process can change its parent process (or any other existing process' environment).

You can, however, create a new environment by creating a new interactive shell with the modified environment.

You have to spawn a new copy of the shell that uses the upgraded environment and has access to the existing stdin, stdout and stderr, and does its reinitialization dance.

You need to do something like use subprocess.Popen to run /bin/bash -i.

So the original shell runs Python, which runs a new shell. Yes, you have a lot of processes running. No it's not too bad because the original shell and Python aren't really doing anything except waiting for the subshell to finish so they can exit cleanly, also.

tzot
  • 92,761
  • 29
  • 141
  • 204
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • Yep, this is what I am currently doing. I was trying to avoid that re-initialization dance. – grieve Nov 04 '08 at 21:34
  • I edited your post fixing some minor typos, and added a parenthesized comment (you might want to remove it if you disagree) – tzot Nov 05 '08 at 11:44
  • 1
    Changing an "existing" process -- while true -- is tangential. Changing the parent process is what confuses everybody; it's unclear to folks that all *nix commands are running in a subprocess. – S.Lott Nov 05 '08 at 11:56
13

It's not possible, for any child process, to change the environment of the parent process. The best you can do is to output shell statements to stdout that you then source, or write it to a file that you source in the parent.

Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
13

I would use the bash eval statement, and have the python script output the shell code

child.py:

#!/usr/bin/env python
print 'FOO="A_Value"'

parent.sh

#!/bin/bash
eval `./child.py`
JimB
  • 104,193
  • 13
  • 262
  • 255
  • This will work in most cases but not if a bash script calls a bash scripts. If it doesn't, change `print ''FOO="A_Value"'` into `print 'export FOO="A_Value"'` – Jorrick Sleijster Jan 13 '22 at 20:53
0

I needed something similar, I ended up creating a script envtest.py with:

import sys, os
sys.stdout = open(os.devnull, 'w')

# Python code with any number of prints (to stdout).
print("This is some other logic, which shouldn't pollute stdout.")

sys.stdout = sys.__stdout__
print("SomeValue")

Then in bash:

export MYVAR=$(python3 envtest.py)
echo "MYVAR is $MYVAR"

Which echos the expected: MYVAR is SomeValue

André C. Andersen
  • 8,955
  • 3
  • 53
  • 79