1

I have many bash scripts to help set my current session environment variables. I need the env variables set so I can use the subprocess module to run commands in my python scripts. This is how I execute the bash scripts:

. ./file1.sh

Below is the beginning of the bash script:

echo "Setting Environment Variable..."
export HORCMINST=99
echo $HORCMINST
...

Is there a way to call these bash scripts from a python script or do something similar within a python script?

clarkus978
  • 574
  • 3
  • 10
  • 22

3 Answers3

2

Using shell=True With Your Existing Script

First, in terms of the very simplest thing -- if you're using shell=True, you can tell the shell that starts to run the contents of your preexisting script unmodified.

That is to say -- if you were initially doing this:

subprocess.Popen(['your-command', 'arg1', 'arg2'])

...then you can do the following to execute that same command, with almost the same security guarantees (the only additional vulnerabilities, so long as the contents of file1.sh are trusted, are to out-of-band issues such as shellshock):

# this has the security of passing explicit out-of-band args
# but sources your script before the out-of-process command
subprocess.Popen(['. "$1"; shift; exec "$@"', "_", "./file1.sh",
    "your-command", "arg1", "arg2"], shell=True)

Using /proc/self/environ to export environment variables in a NUL-delimited stream

The ideal thing to do is to export your environment variables in an unambiguous form -- a NUL-delimited stream is ideal -- and then parse that stream (which is in a very unambiguous format) in Python.

Assuming Linux, you can export the complete set of environment variables as follows:

# copy all our environment variables, in a NUL-delimited stream, to myvars.environ
cat </proc/self/environ >myvars.environ

...or you can export a specific set of variables by hand:

for varname in HORCMINST PATH; do
  printf '%s=%s\0' "$varname" "${!varname}"
done >myvars.environ

Reading and parsing a NUL-delimited stream in Python

Then you just need to read and parse them:

#!/usr/bin/env python
env = {}
for var_def in open('myvars.environ', 'r').read().split('\0'):
  (key, value) = var_def.split('=', 1)
  env[key] = value

import subprocess
subprocess.Popen(['your-command', 'arg1', 'arg2'], env=env)

You could also immediately apply those variables by running os.environ[key]=value.


Reading and parsing a NUL-delimited stream in bash

Incidentally, that same format is also easy to parse in bash:

while IFS= read -r -d '' var_def; do
  key=${var_def%%=*}
  value=${var_def#*=}
  printf -v "$key" '%s' "$value"
  export "$key"
done <myvars.environ

# ...put the rest of your bash script here

Now, why a NUL-delimited stream? Because environment variables are C strings -- unlike Python strings, they can't contain NUL. As such, NUL is the one and only character that can be safely used to delimit them.

For instance, someone who tried to use newlines could be stymied by an environment variable that contained a literal newline -- and if someone is, say, embedding a short Python script inside an environment variable, that's a very plausible event!

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thank you for going above and beyond with your response. I have already been using `shell=True` for my python scripts. I will try the ideal approach and export my environment variables in the unambiguous form as you mentioned. – clarkus978 Jan 18 '17 at 15:13
0

You should consider the Python builtin os module. The attribute os.environ is a dictionary of environment variables that you can read, e.g.

import os
os.environ["USER"]

You cannot, however, write bash environment variables from the child process (see e.g., How to use export with Python on Linux).

Community
  • 1
  • 1
innisfree
  • 2,044
  • 1
  • 14
  • 24
  • Since the OP says they're trying "to use the subprocess module to run commands in my Python scripts", this doesn't look like a case where they're intending to modify the environment of the parent. – Charles Duffy Jan 17 '17 at 23:29
  • I agree that the OP isn't trying to modify environment of parent, but the fact that it's impossible was germane to my answer. – innisfree Jan 17 '17 at 23:32
0

Both of your questions are answered before. You can execute bash scripts from python with something like;

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

See this question running bash commands in python

Better set the environment variables directly in Python, see this question How to set environment variables in Python

Community
  • 1
  • 1
solleks
  • 87
  • 1
  • 4
  • In the context, when the OP says "call these bash scripts from a Python script", they presumably want to update the environment variables that are available to their Python script. The answer given won't work for that (since as soon as the subprocess exits, the variables that it set exited with it). If we don't give them that assumption, then their question is breaking site rules re: appropriate breadth/scope by putting two unrelated items inside a single question. – Charles Duffy Jan 17 '17 at 23:03