Python GUI to execute Bash/ksh environment and shell applications?
As I understand your question, you're trying to execute an external command with one of n
sets of environment variables, where n
is specified by the user. The fact that it's a GUI application doesn't seem relevant to the problem. Please correct me if I'm missing something.
You have several choices:
Execute a command in Python with custom environment variables
Rather than store the environment variables in separate files, you can set them directly with the env
argument to Popen()
:
If env is not
None
, it must be a mapping that defines the environment variables for the new process; these are used instead of inheriting the current process’ environment, which is the default behavior.
So instead of having app1.sh
, app2.sh
, app3.sh
, and so on, store your environment variable sets in Python, and add them to the environment you pass to Popen()
, like so:
env_vars = { 1: { 'DIR': '/some/location/', 'LICENSE': '/some/license/' 'SOMEVAR': 'some value' }, 2: ...}...environ_copy = dict(os.environ)environ_copy.update(env_vars[n])subprocess.Popen('external_application', shell=True, env=environ_copy, ...)
Modify the environment with a wrapper script
If your environment vars must live in separate, dedicated shell scripts something like your helper is the best you can do.
We can clean it up a little, though:
#!/usr/bin/env bashif source "$1"; then # Set up env variables external_app # Runs the actual applicationelse echo "Error executing $1" 2>/dev/stderr exit 1 # Return a non-zero exit statusfi
This lets you pass app1.sh
to the script, rather than create n
separate helper files. It's not clear why you're using &
to background the process - Popen
starts a separate process which doesn't block the Python process from continuing. With subprocess.PIPE
you can use Popen.communicate()
to get back the process' stdout and stderr.
Avoid setting environment variables at all
If you have control of external_process
(i.e. you wrote it, and can modify it), you'd be much better off changing it to use command line arguments, rather than environment variables. That way you could call:
subprocess.Popen('external_command', '/some/location/', '/some/license/', 'some value')
and avoid needing shell=True
or a wrapper script entirely. If external_command
expects a number of variables it might be better to use --flags
(e.g. --dir /some/location/
) rather than positional arguments. Most programming languages have a argument processing library (or several) to make this easy; Python provides argparse
for this purpose.
Using command line arguments rather than environment variables will make external_process
much more user friendly, especially for the use case you're describing. This is what I would suggest doing.