start - using bash commands in python




Emulation Bash 'Quelle' in Python (4)

Anstatt dass Ihr Python-Skript das Bash-Skript init_env , wäre es einfacher und eleganter, eine Wrapper- init_env und dann Ihr Python-Skript mit der modifizierten Umgebung auszuführen.

#!/bin/bash
source init_env
/run/python/script.py

Ich habe ein Skript, das ungefähr so ​​aussieht:

export foo=/tmp/foo                                          
export bar=/tmp/bar

Jedes Mal, wenn ich baue, führe ich 'source init_env' aus (wobei init_env das obige Skript ist), um einige Variablen einzurichten.

Um dasselbe in Python zu erreichen, habe ich diesen Code ausgeführt,

reg = re.compile('export (?P<name>\w+)(\=(?P<value>.+))*')
for line in open(file):
    m = reg.match(line)
    if m:
        name = m.group('name')
        value = ''
        if m.group('value'):
            value = m.group('value')
        os.putenv(name, value)

Aber dann hat jemand entschieden, dass es nett wäre, eine Zeile wie die folgende in die Datei init_env :

export PATH="/foo/bar:/bar/foo:$PATH"     

Offensichtlich ist mein Python-Skript auseinander gefallen. Ich könnte das Python-Skript ändern, um mit dieser Zeile init_env , aber dann bricht es später ab, wenn jemand eine neue Funktion zur Verwendung in der init_env Datei init_env .

Die Frage ist, ob es eine einfache Möglichkeit gibt, einen Bash-Befehl auszuführen und meinen os.environ ändern.


Beispielumhüllung @ Brians ausgezeichnete Antwort in einer Funktion:

import json
import subprocess

# returns a dictionary of the environment variables resulting from sourcing a file
def env_from_sourcing(file_to_source_path, include_unexported_variables=False):
    source = '%ssource %s' % ("set -a && " if include_unexported_variables else "", file_to_source_path)
    dump = '/usr/bin/python -c "import os, json; print json.dumps(dict(os.environ))"'
    pipe = subprocess.Popen(['/bin/bash', '-c', '%s && %s' % (source, dump)], stdout=subprocess.PIPE)
    return json.loads(pipe.stdout.read())

Ich verwende diese Dienstprogrammfunktion zum Lesen von aws-Anmeldedaten und Andocken von .env-Dateien mit include_unexported_variables=True .


Die Antwort von @ lesmana für Python 3 wurde aktualisiert. Beachten Sie die Verwendung von env -i die verhindert, dass externe Umgebungsvariablen gesetzt / zurückgesetzt werden (möglicherweise fälschlicherweise aufgrund der fehlenden Handhabung für mehrzeilige env-Variablen).

import os, subprocess
if os.path.isfile("init_env"):
    command = 'env -i sh -c "source init_env && env"'
    for line in subprocess.getoutput(command).split("\n"):
        key, value = line.split("=")
        os.environ[key]= value

Pickle verwenden:

import os, pickle
# For clarity, I moved this string out of the command
source = 'source init_env'
dump = '/usr/bin/python -c "import os,pickle;print pickle.dumps(os.environ)"'
penv = os.popen('%s && %s' %(source,dump))
env = pickle.loads(penv.read())
os.environ = env

Aktualisiert:

Dies verwendet json, subprocess und verwendet explizit / bin / bash (für Ubuntu-Unterstützung):

import os, subprocess as sp, json
source = 'source init_env'
dump = '/usr/bin/python -c "import os, json;print json.dumps(dict(os.environ))"'
pipe = sp.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=sp.PIPE)
env = json.loads(pipe.stdout.read())
os.environ = env




bash