ftw
ftw

Reputation: 385

Source shell script and access exported variables from os.environ

I have a shell script where certain parameters are being set like:
k.sh:

export var="value"
export val2="value2"

Then I have a python script where i am calling the shell script and want to use these enviornment variables
ex1.py:

import subprocess
import os
subprocess.call("source k.sh",shell=True)
print os.environ["var"]

But I am getting a KeyError
How can I use these shell variables in my Python script?

Upvotes: 6

Views: 4409

Answers (6)

Paul Hashmi
Paul Hashmi

Reputation: 466

If your on windows you could set an environment variable with powershell

os.system("powershell.exe [System.Environment]::SetEnvironmentVariable('key', 'value','User')")

its worth noting before your application can use the variables you will need to restart you application to allow it to read the updated variables...

then you can access with

yourValue = os.environ['key']

Upvotes: 0

Adel Ahmadyan
Adel Ahmadyan

Reputation: 174

/u/unutbu already answered this question. However I fixed couple of bugs in his code:

def run_external_script(script):
    if is_windows():
        command = script+" && python -c \"import os; print dict(os.environ)\""
    else:
        command = ". "+ script+" && python -c 'import os; print dict(os.environ)'"

    output = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True).communicate()[0]
    r = re.compile('{.*}')
    m = r.search(output)
    try:
        env = eval(m.group(0))
    except:
        error( "Something went wrong in " + script )
        error( output )
    return env

There are couple of small differences:

  • This code works both on windows/linux
  • I replaced subprocess.check_output with subprocess.call, check_output requires Python 2.7
  • When I ran his code, there std out of the script would also got printed in the output variables. So I used a re to grab the dictionary everything between two {}, such as {'var1'=1, 'var2'='x'}.
  • instead of using json, I used python's eval. There is a chance of injection, so use it at your own risk. such as {; exit(1); }

Upvotes: 0

Diego Torres Milano
Diego Torres Milano

Reputation: 69208

If you want to set the environment and then run a Python script, well, set the environment and run the Python script using runner:

runner:

#! /bin/bash
. k.sh
exec ex1.py

and that's it.

ex1.py:

#import subprocess
import os
#subprocess.call("source k.sh",shell=True)
print os.environ["var"]

Upvotes: 2

unutbu
unutbu

Reputation: 879471

You could source k.sh and run a Python one-liner to print the contents of os.environ as JSON. Then use json.loads to convert that output back into a dict in your main process:

import subprocess
import os
import json
PIPE = subprocess.PIPE
output = subprocess.check_output(
    ". ~/tmp/k.sh && python -c 'import os, json; print(json.dumps(dict(os.environ)))'",
    shell=True)
env = json.loads(output)
print(env["var"])

yields

value

Upvotes: 2

Torxed
Torxed

Reputation: 23480

As pointed out by chepner. You'r subprocess part is runnign individually. Working with environment variables has to be done prior to launching the python script..

For instance:

C:\Users\anton\Desktop\githubs>echo %x%
y

C:\Users\anton\Desktop\githubs>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ['x']
'y'
>>>

Sourcing your environment variables prior to launching the script will traverse down however, or if you execute multiple commands to the subprocess call that would also be great after you sourced it. for instance:

import subprocess
import os
x = subprocess.call("source k.sh",shell=True, STDIN=subprocess.PIPE, STDOUT=subprocess.PIPE)
y = subprocess.call("echo $var",shell=True, STDIN=x.stdout, STDOUT=subprocess.PIPE)

Never tried that tho, as mentioned. Source it before launch.

Upvotes: 0

chepner
chepner

Reputation: 531125

subprocess.call starts a shell in a new process, which calls source. There is no way to modify the environment within your process from a child process.

Upvotes: 2

Related Questions