Emulation Bash 'Quelle' in Python

Ich habe ein Skript, das so aussieht:

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

Jedes Mal, wenn ich baue, laufe ich 'source init_env' (wo init_env das obige Skript ist), um einige Variablen einzurichten.

Um das gleiche in Python zu erreichen, hatte ich diesen Code laufen,

 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 sich jemand entschieden, dass es schön wäre, eine Zeile wie die folgenden der init_env Datei init_env :

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

Offensichtlich fiel mein Python-Skript auseinander. Ich könnte das Python-Skript ändern, um diese Zeile zu behandeln, aber dann wird es nur später brechen, wenn jemand kommt mit einem neuen Feature, um in der init_env Datei verwenden.

Die Frage ist, ob es einen einfachen Weg, um einen Bash-Befehl und lassen Sie es meine os.environ ändern?

6 Solutions collect form web for “Emulation Bash 'Quelle' in Python”

Das Problem mit deinem Ansatz ist, dass du versuchst, Bash-Skripte zu interpretieren. Zuerst versuchen Sie einfach, die Export-Anweisung zu interpretieren. Dann bemerkst du, dass die Leute eine variable Erweiterung verwenden. Später werden die Menschen in ihre Akten geraten oder Substitutionen verarbeiten. Am Ende haben Sie einen vollen geblasenen Bash-Skript-Interpreter mit einem Gazillion Bugs. Tu das nicht

Lassen Sie Bash die Datei für Sie interpretieren und dann die Ergebnisse sammeln.

Du kannst es so machen:

 #! /usr/bin/env python import os import pprint import subprocess command = ['bash', '-c', 'source init_env && env'] proc = subprocess.Popen(command, stdout = subprocess.PIPE) for line in proc.stdout: (key, _, value) = line.partition("=") os.environ[key] = value proc.communicate() pprint.pprint(dict(os.environ)) 

Vergewissern Sie sich, dass Sie Fehler behandeln, falls bash die source init_env nicht source init_env , oder bash selbst nicht ausgeführt wird, oder Unterprozeß fehlschlägt, bash oder andere Fehler auszuführen.

Lesen Sie die Dokumentation zum Unterprozess für weitere Details.

Hinweis: Hier werden nur Variablen erfasst, die mit der export , da env nur exportierte Variablen druckt.

Genießen.

Beachten Sie, dass die Python-Dokumentation sagt, dass Sie, wenn Sie die Umgebung manipulieren os.environ , os.environ direkt anstelle von os.putenv() manipulieren os.environ . Ich denke, dass ein Bug, aber ich abschweifen.

Mit 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 explizit verwendet / 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 

Anstatt Ihre Python-Skript-Quelle das bash-Skript zu haben, wäre es einfacher und eleganter, eine Wrapper- init_env und dann dein Python-Skript mit der geänderten Umgebung auszuführen.

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

Aktualisiert @ lesmanas Antwort für Python 3. Beachten Sie die Verwendung von env -i die verhindert, dass Fremdumgebungsvariablen gesetzt / zurückgesetzt werden (potenziell falsch gegeben mangelnde Handhabung für multiline 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 

Schamloser Stecker.

Ich habe den Sultan geschaffen, um mich um dieses genaue Problem zu kümmern. Ich fühlte, dass das Subprocess-Modul nicht sehr pythonisch war, und so schuf ich eine Abstraktion darüber, also ist es pythonischer.

https://github.com/aeroxis/sultan

 execfile('filename') 

Sollte es tun

  • Wie kann ich 'Git Pull' aus Python?
  • Gemeinsame Lisp: Starten Sie den Teilprozess mit dem unterschiedlichen Arbeitsverzeichnis als der Lisp-Prozess
  • Wie installiere ich eine DMG-Datei von der Kommandozeile?
  • Ändern Sie die erste Zeile einer Datei mit bash
  • Bash-Stil-Prozess-Substitution mit Python's Popen
  • Bash: Variable in einfachem Zitat
  • Shell: Sofortiger Benutzer, um einen Verzeichnispfad einzugeben
  • Kill python Prozess mit pkill python
  • Fehlermeldung des Unterprozeßbefehls speichern
  • Automatisieren Sie Input in Python-Aufforderungen
  • Die Ausgabe eines anderen Programms als Eingang auf der Fliege erhalten
  • Python ist die beste Programmiersprache der Welt.