440 Stimmen

Python subprocess/Popen mit einer geänderten Umgebung

Ich glaube, dass die Ausführung eines externen Befehls mit einer leicht veränderten Umgebung ein sehr häufiger Fall ist. So mache ich es in der Regel auch:

import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

Ich habe das Gefühl, dass es einen besseren Weg gibt; sieht das gut aus?

620voto

Daniel Burke Punkte 5254

Ich denke os.environ.copy() ist besser, wenn Sie nicht die Absicht haben, die os.environ für den aktuellen Prozess zu ändern:

import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

119voto

skyking Punkte 13037

Das hängt davon ab, was das Problem ist. Wenn es darum geht, die Umgebung zu klonen und zu ändern, könnte eine Lösung sein:

subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))

Aber das hängt davon ab, dass die ersetzten Variablen gültige Python-Bezeichner sind, was sie meistens sind (wie oft stößt man auf Umgebungsvariablennamen, die nicht alphanumerisch+Unterstrich sind, oder auf Variablen, die mit einer Zahl beginnen).

Andernfalls könnten Sie etwas schreiben wie:

subprocess.Popen(my_command, env=dict(os.environ, 
                                      **{"Not valid python name":"value"}))

In dem sehr merkwürdigen Fall (wie oft verwenden Sie Steuercodes oder Nicht-Ascii-Zeichen in Namen von Umgebungsvariablen?), dass die Schlüssel der Umgebung bytes kann man (in Python 3) nicht einmal dieses Konstrukt verwenden.

Wie Sie sehen können, profitieren die hier verwendeten Techniken (insbesondere die erste) von den Schlüsseln der Umgebung, die normalerweise gültige Python-Bezeichner sind und auch im Voraus bekannt sind (zum Zeitpunkt der Programmierung), der zweite Ansatz hat Probleme. In Fällen, in denen das nicht der Fall ist, sollten Sie wahrscheinlich nach ein anderer Ansatz .

49voto

skovorodkin Punkte 7938

Mit Python 3.5 kann man das so machen:

import os
import subprocess

my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}

subprocess.Popen(my_command, env=my_env)

Hier landen wir bei einer Kopie von os.environ und außer Kraft gesetzt PATH Wert.

Ermöglicht wurde dies durch PEP 448 (Zusätzliche Verallgemeinerungen zum Auspacken).

Ein weiteres Beispiel. Wenn Sie eine Standardumgebung haben (d.h. os.environ ) und einem Diktat, mit dem Sie die Standardeinstellungen überschreiben möchten, können Sie dies folgendermaßen ausdrücken:

my_env = {**os.environ, **dict_with_env_variables}

26voto

SilentGhost Punkte 285785

Können Sie verwenden my_env.get("PATH", '') anstelle von my_env["PATH"] im Falle PATH irgendwie nicht in der ursprünglichen Umgebung definiert, aber ansonsten sieht es gut aus.

21voto

MFB Punkte 17505

Um eine Umgebungsvariable temporär zu setzen, ohne das os.envrion-Objekt zu kopieren, mache ich folgendes:

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username@foobar.com::'], stdout=subprocess.PIPE)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X