it-swarm.com.de

Warum können in Python eingestellte Umgebungsvariablen nicht bestehen bleiben?

Ich hatte gehofft, ein Python-Skript zu schreiben, um einige geeignete Umgebungsvariablen zu erstellen, indem ich das Skript in einem beliebigen Verzeichnis ausführte. Ich werde etwas Simulationscode ausführen. Ich habe gelesen, dass ich kein Skript schreiben kann, in dem diese Umgebungsvariablen bestehen bleiben das Mac OS-Terminal. Also zwei Dinge:

Ist das wahr?

und

Es scheint, dass es nützliche Dinge zu tun wäre; Warum ist es überhaupt nicht möglich?

37
physicsmichael

Mit Python ist das nicht möglich, aber ein paar clevere Bash-Tricks können etwas Ähnliches tun. Der Grund ist folgender: Umgebungsvariablen existieren in einem pro-Prozess-Speicherplatz. Wenn ein neuer Prozess mit Fork () erstellt wird, erbt er die Umgebungsvariablen des übergeordneten Elements. Wenn Sie eine Umgebungsvariable in Ihrer Shell (z. B. bash) wie folgt festlegen: 

export VAR="foo"

Was Sie tun, sagt bash, die Variable VAR in ihrem Prozessbereich auf "foo" zu setzen. Wenn Sie ein Programm ausführen, verwendet bash gork () und anschließend exec (), um das Programm auszuführen. Daher erben alle von bash aus ausgeführten Bash-Umgebungsvariablen. 

Angenommen, Sie möchten einen Bash-Befehl erstellen, der einige Umgebungsvariable DATA mit Inhalt aus einer Datei in Ihrem aktuellen Verzeichnis namens ".data" setzt. Zunächst benötigen Sie einen Befehl, um die Daten aus der Datei zu holen: 

cat .data

Das druckt die Daten. Jetzt möchten wir einen Bash-Befehl erstellen, um diese Daten in einer Umgebungsvariablen festzulegen: 

export DATA=`cat .data`

Dieser Befehl nimmt den Inhalt von .data in die Umgebungsvariable DATA. Wenn Sie das nun in einen Alias-Befehl einfügen, haben Sie einen Bash-Befehl, der Ihre Umgebungsvariable festlegt:

alias set-data="export DATA=`cat .data`"

Sie können diesen Aliasbefehl in die .bashrc- oder .bash_profile -Dateien Ihres Home-Verzeichnisses einfügen, damit dieser Befehl in jeder neuen bash-Shell verfügbar ist, die Sie starten. 

31
Benson

Eine Problemumgehung besteht darin, export-Befehle auszugeben und die übergeordnete Shell dies auswerten zu lassen.

thescript.py:

import pipes
import random
r = random.randint(1,100)
print("export BLAHBLAH=%s" % (pipes.quote(str(r))))

..und der Bash-Alias ​​(das gleiche kann in den meisten Shells gemacht werden ... sogar tcsh!):

alias setblahblahenv="eval $(python thescript.py)"

Verwendungszweck:

$ echo $BLAHBLAH

$ setblahblahenv
$ echo $BLAHBLAH
72

Sie können beliebigen Shell-Code ausgeben, einschließlich mehrerer Befehle wie:

export BLAHBLAH=23 SECONDENVVAR='something else' && echo 'everything worked'

Vergessen Sie nicht, auf dynamisch erzeugte Ausgaben zu achten (das pipes.quote-Modul ist dafür gut geeignet).

17
dbr

Wenn Sie Umgebungsvariablen in einem Python-Skript (oder einem anderen Skript oder Programm) festlegen, hat dies keine Auswirkungen auf die übergeordnete Shell.

Bearbeiten Sie die Klarstellung: Die Antwort auf Ihre Frage lautet also Ja, es ist wahr . Sie können jedoch aus einem Shell-Skript exportieren und es mithilfe des Punktaufrufs als Quelle verwenden

in fooexport.sh

export FOO="bar"

bei der Eingabeaufforderung

$ . ./fooexport.sh
$ echo $FOO
bar
3
Stefano Borini

Was ich gerne mache, ist die Verwendung von/usr/bin/env in einem Shell-Skript, um meine Befehlszeile zu "umbrechen", wenn ich mich in ähnlichen Situationen befinde:

#!/bin/bash

/usr/bin/env NAME1="VALUE1" NAME2="VALUE2" ${*}

Nennen wir dieses Skript also "myappenv". Ich habe es in mein $ HOME/bin-Verzeichnis geschrieben, das ich in meinem $ PATH habe.

Jetzt kann ich jeden Befehl in dieser Umgebung aufrufen, indem Sie einfach "myappenv" als solches voranstellen:

myappenv dosometask -xyz

Andere veröffentlichte Lösungen funktionieren auch, aber dies ist meine persönliche Präferenz. Ein Vorteil ist, dass die Umgebung vorübergehend ist. Wenn ich in der Shell arbeite, ist nur der Befehl, den ich aufrufe, von der geänderten Umgebung betroffen.

Geänderte Version basierend auf neuen Kommentaren

#!/bin/bash

/usr/bin/env G4WORKDIR=$PWD ${*}

Sie könnten das alles auch in einem Pseudonym abschließen. Ich ziehe den Ansatz des Wrapper-Skripts vor, da ich dazu neige, andere Umgebungen vorzubereiten, was die Wartung für mich einfacher macht.

2
Joe Holloway

Das ist generell nicht möglich. Der für Python erstellte neue Prozess kann sich nicht auf die Umgebung des übergeordneten Prozesses auswirken. Das übergeordnete Element kann sich nicht auf das untergeordnete Element auswirken, das übergeordnete Element kann jedoch die Umgebung des untergeordneten Objekts als Teil der neuen Prozesserstellung einrichten.

Vielleicht können Sie sie in .bashrc, .profile oder dem entsprechenden Skript "Läuft beim Anmelden" oder "Läuft bei jeder neuen Terminalsitzung" in MacOS festlegen.

Sie können das Simulationsprogramm auch mit Python in der gewünschten Umgebung starten. (Verwenden Sie den Parameter env zum Subprozess.Popen ( http://docs.python.org/library/subprocess.html ))

import subprocess, os
os.chdir('/home/you/desired/directory')
subprocess.Popen(['desired_program_cmd', 'args', ...], env=dict(SOMEVAR='a_value') )

Oder Sie könnten Python so ein Shell-Skript in eine Datei mit der Erweiterung .sh schreiben lassen: 

export SOMEVAR=a_value
cd /home/you/desired/directory
./desired_program_cmd

und dann chmod +x und von überall ausführen.

1
Joe Koberg

Wie von Benson geantwortet, aber der beste Hacker ist das Erstellen einer einfachen Bash-Funktion, um die Argumente zu erhalten:

upsert-env-var (){ eval $(python upsert_env_var.py $*); }

Sie können mit den Argumenten tun, was Sie in Ihrem Python-Skript wollen. Um einfach eine Variable hinzuzufügen, verwenden Sie Folgendes:

var = sys.argv[1]
val = sys.argv[2]
if os.environ.get(var, None):
    print "export %s=%s:%s" % (var, val, os.environ[var])
else:
    print "export %s=%s" % (var, val)

Verwendungszweck:

upsert-env-var VAR VAL
0
Niall