How to Change the Environment of a Parent Process in Python

How to set environment variables of parent shell in Python?

This isn't possible.

Child processes inherit their environments from their parents rather than share them. Therefore any modifications you make to your environment will be reflected only in the child (python) process. Practically, you're just overwriting the dictionary the os module has created based on your environment of your shell, not the actual environment variables of your shell.

https://askubuntu.com/questions/389683/how-we-can-change-linux-environment-variable-in-python

Why can't environmental variables set in python persist?

Is it possible to change the Environment of a parent process in Python?

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.

Change parent shell's environment from a subprocess

This can only be done with the parent shell's involvement and assistance. For a real-world example of a program that does this, you can look at how ssh-agent is supposed to be used:

eval "$(ssh-agent -s)"

...reads the output from ssh-agent and runs it in the current shell (-s specifies Bourne-compatible output, vs csh).


If you're using Python, be sure to use pipes.quote() (or, for Python 3.x, shlex.quote()) to process your output safely:

import pipes
dirname='/path/to/directory with spaces'
foo_val='value with * wildcards * that need escaping and \t\t tabs!'
print 'cd %s; export FOO=%s;' % (pipes.quote(dirname), pipes.quote(foo_val))

...as careless use can otherwise lead to shell injection attacks.


By contrast, if you're writing this as an external script in bash, be sure to use printf %q for safe escaping (though note that its output is targeted for other bash shells, not for POSIX sh compliance):

#!/bin/bash
dirname='/path/to/directory with spaces'
foo_val='value with * wildcards * that need escaping and \t\t tabs!'
printf 'cd %q; export FOO=%q;' "$dirname" "$foo_val"

If, as it appears from your question, you want your command to appear to be written as a native shell function, I would suggest wrapping it in one (this practice can also be used with command_not_found_handle). For instance, installation can involve putting something like the following in one's .bashrc:

my_command() {
eval "$(command /path/to/my_command.py "$@")"
}

...that way users aren't required to type eval.

How to set parent process' shell env from child process

Environment variables are copied from parent to child, they are not shared or copied in the other direction. All export does is make an environment variable in the child, so its children will see it.

Simplest way is to echo in the child process (I'm assuming it is a shell script) and capture it in python using a pipe.

Python:

import subprocess

proc = subprocess.Popen(['bash', 'gash.sh'], stdout=subprocess.PIPE)

output = proc.communicate()[0]

print "output:", output

Bash (gash.sh):

TEMP_VAR='yellow world'
echo -n "$TEMP_VAR"

Output:

output: yellow world

Set environment variable of calling bash script in python

you cannot propagate an environment variable to the parent process. But you can print the variable, and assign it back to the variable name from your shell:

VarFromFirstScript=$(python myOtherScript.py $VarFromFirstScript)

you must not print anything else in your code, or using stderr

sys.stderr.write("Running some code...\n")
VarFromFirstScript = someFunc()
sys.stdout.write(VarFromFirstScript)

an alternative would be to create a file with the variables to set, and make it parse by your shell (you could create a shell that the parent shell would source)

import shlex
with open("shell_to_source.sh","w") as f:
f.write("VarFromFirstScript={}\n".format(shlex.quote(VarFromFirstScript))

(shlex.quote allows to avoid code injection from python, courtesy Charles Duffy)

then after calling python:

source ./shell_to_source.sh

Re-read environment of parent process in python

For me it looks that you are asking for inter-process communication between a bash script and a python program.

I'm not completely sure about all your requirements, but it might be a candidate for a FIFO (named pipe):

1) make the fifo:

mkfifo batch_control

2) Start the python - server, which reads from the fifo. (Note: the following is only a minimalistic example; you must adapt things:

while True:
fd = file("batch_control", "r")
for cmd in fd:
print("New command [%s]" % cmd[:-1])
fd.close()

3) From the bash script you can than 'send' things to the python server by echo-ing strings into the fifo:

$ echo "newsize 800" >batch_control
$ echo "newjob /bin/ps" >batch_control

The output of the python server is:

New command [newsize 800]
New command [newjob /bin/ps]

Hope this helps.

Get Changed Environment Variable in Python

I guess you can use os.getenv() to get the value of an environment variable any time, and this will reflect the most up-to-date state.

Update: note that there is no such thing as one "global" environment, at least not on Linux. Quoting Wikipedia:

In all Unix and Unix-like systems, each process has its own private set of environment variables. By default, when a process is created it inherits a duplicate environment of its parent process, except for explicit changes made by the parent when it creates the child.

Therefore, if you launch (fork) two processes from the same parent process (such as bash), and change an environment variable in one of the processes, the other process won't see it because it uses another copy of the environment of the parent process. Similarly, if you change the environment in the parent process after having launched the child processes, the child processes won't see the change because they have already created their private copy of the environment.



Related Topics



Leave a reply



Submit