Eine env-Variable exportieren, um in allen Sub-Shells verfügbar zu sein und geändert zu werden?

22

Angenommen, ich habe

export MY_VAR=0

in ~/.bashrc.

Ich habe ein Gnomenterminal geöffnet, und in diesem Terminal ändere ich den $MY_VARWert auf 200. Also, wenn ich es tue

echo $MY_VAR

In diesem Terminal 200wird angezeigt.

Jetzt habe ich einen weiteren Tab in meinem Gnome-Terminal geöffnet und mache

echo $MY_VAR

... und stattdessen habe 200ich 0.

Was kann ich tun, um den 200-Wert beizubehalten, wenn ein Terminal eine Umgebungsvariable ändert und diese Änderung (Einstellung auf 200) für alle nachfolgenden Sub-Shells und dergleichen verfügbar macht? Ist das möglich?

Jemand verwendet Sie immer noch MS-DOS
quelle

Antworten:

23

Eine Kopie der Umgebung breitet sich in Unterschalen aus. Dies funktioniert also wie folgt:

$ export MY_VAR=200
$ bash
$ echo $MY_VAR
200

Da es sich jedoch um eine Kopie handelt, können Sie diesen Wert nicht auf die übergeordnete Shell übertragen - zumindest nicht durch Ändern der Umgebung.

Es hört sich so an, als ob Sie tatsächlich einen Schritt weiter gehen möchten, nämlich etwas, das sich wie eine globale Variable verhält und von "Geschwister" -Shells gemeinsam genutzt wird, die separat vom übergeordneten Element initiiert wurden - wie Ihr neuer Tab in Gnome Terminal.

Meistens lautet die Antwort "Sie können nicht, weil Umgebungsvariablen nicht so funktionieren". Es gibt jedoch noch eine andere Antwort: Sie können immer etwas auf den Kopf stellen. Ein Ansatz wäre, den Wert der Variablen in eine Datei zu schreiben ~/.myvarund ihn dann in die Datei einzuschließen ~/.bashrc. Dann beginnt jede neue Shell mit dem Wert, der aus dieser Datei gelesen wurde.

Sie können noch einen Schritt weiter gehen - geben Sie ~/.myvardas Format ein MYVAR=200und legen Sie fest PROMPT_COMMAND=source ~/.myvar, dass der Wert jedes Mal neu gelesen wird, wenn Sie eine neue Eingabeaufforderung erhalten. Es ist immer noch nicht ganz eine gemeinsame globale Variable, aber es fängt an, wie es zu handeln. Es wird jedoch erst aktiviert, wenn eine Eingabeaufforderung zurückkommt. Dies kann je nach dem, was Sie versuchen, eine ernsthafte Einschränkung darstellen.

Und dann ist es natürlich das nächste, automatisch Änderungen zu schreiben~/.myvar . Das wird etwas komplizierter, und ich werde an dieser Stelle aufhören, denn Umgebungsvariablen waren eigentlich nicht als Kommunikationsmechanismus zwischen den Shells gedacht, und es ist besser, einfach einen anderen Weg zu finden, dies zu tun.

mattdm
quelle
10
Ich kann die Muschel unter der Folter quietschen hören
Ja entschuldigung. Deshalb habe ich aufgehört. :)
mattdm
"Das soll etwas machen, das sich wie eine globale Variable verhält" - Nun, genau das habe ich versucht zu erreichen. Die ~ / .myvar ist nicht schön, aber es funktioniert. Haben Sie noch einen Vorschlag?
Jemand verwendet Sie immer noch MS-DOS
2
Lass uns einen Schritt zurücktreten. Warum möchten Sie eine globale Variable?
Mattdm
1
@mattdm: Ich habe einige "Bürokratien", denen ich gehorchen muss. Einer von ihnen ist eine Reihe von Codes, die ich zusammen mit einem Kommentar festschreiben muss. Diese Codes befinden sich jetzt in einer Ordnerhierarchie (home / user / projects / projectcode / code1 / code2). Ich habe eine Funktion erstellt, die Code1 und Code2 in env vars extrahiert (wenn ich also eine Aktivität ausführen muss, rufe ich einfach die Funktion im Verzeichnis mit den Codes auf). Wenn ich sie festschreibe, verwende ich vim und es gibt einige Funktionen, die dies tun Lesen Sie diese Vars und geben Sie automatisch einen Kommentar ein. Ich denke, dass die Verwendung von Dateien dafür eine Lösung sein kann.
Jemand benutzt Sie immer noch MS-DOS
13

Angenommen, ich habe export MY_VAR=0in ~/.bashrc.

Das ist dein Fehler genau dort. Sie sollten Ihre Umgebungsvariablen definieren ~/.profile, die beim Anmelden ~/.bashrcgelesen werden. Sie werden jedes Mal gelesen, wenn Sie eine Shell starten. Wenn Sie die innere Shell starten, wird diese überschrieben MY_VAR. Wenn Sie das nicht getan hätten, würde sich Ihre Umgebungsvariable nach unten ausbreiten.

Weitere Informationen zu ~/.bashrcvs ~/.profilefinden Sie in meinen vorherigen Beiträgen zu diesem Thema .

Beachten Sie, dass eine Aufwärtsausbreitung (Abrufen eines geänderten Werts aus der Subshell, der automatisch in der übergeordneten Shell widergespiegelt wird) nicht möglich ist (Punkt).

Gilles 'SO - hör auf böse zu sein'
quelle
3

Verwenden Sie überhaupt keine Umgebungsvariablen. Verwenden Sie Dateien.

Verwenden Sie Sperrdateien und kleine Front-End-Updater-Skripte, um zu verhindern, dass Prozesse beim Aktualisieren / Lesen der Datei aufeinandertreffen, und aktualisieren Sie eine Datei nur mit $ 1, wenn sie nicht gesperrt ist. Sperrdateien werden implementiert, indem grundsätzlich geprüft wird, ob eine bestimmte Datei vorhanden ist (/var/run/yourscript.lck). Wenn dies der Fall ist, warten Sie, bis die Datei eine Weile verschwindet, und schlagen Sie fehl, wenn dies nicht der Fall ist. Außerdem müssen Sie die Sperrdatei löschen, wenn Sie mit dem Aktualisieren der Datei fertig sind.

Stellen Sie sich auf eine Situation ein, in der ein Skript eine Datei nicht aktualisieren kann, weil die Datei ausgelastet ist.

LawrenceC
quelle
8
Ein Trick: Verwenden Sie Verzeichnisse anstelle von Dateien zum Sperren, da dies mkdirals atomares Testen und Erstellen funktioniert.
Mattdm
1
Wenn ihr über das Sperren reden wollt, dann nutzt ihr vielleicht auchflock(2)
Ehtesh Choudhury
@mattdm Ich habe festgestellt, dass ein Symlink ln -s dummy lockfile(auch wenn er defekt ist) möglicherweise auch funktioniert, da er fehlschlägt, wenn der Symlink bereits vorhanden ist. Ich frage mich, wie ich testen kann, ob das wirklich 100% sicher ist.
Aquarius Power
1

Als ich diese Frage gerade gegoogelt habe, habe ich versucht, das Problem der Aktualisierung von Status (dh Shell-Variablen) aus Subshells heraus zu lösen. Damit man Variablen zum Beispiel innerhalb einer Pipeline zuweisen kann - und die Zuordnung für das übergeordnete Element transparent ist.

Dies ist natürlich nicht auf einfache Weise möglich, da einzelne Teile einer Pipeline in Subshells ausgeführt werden, die forkvon der übergeordneten Shell stammen und daher über einen Speicher verfügen, der beim Schreiben kopiert werden kann. Ich nahm jedoch an, dass eine schlanke und transparente Lösung auf der Grundlage von IPCs mit " gemeinsam genutztem Speicher " möglich sein könnte .

Und ich habe sogar eine Implementierung von genau diesem Design gefunden ... aber es ist in Perl.

Füge diese Antwort trotzdem als mögliche Lösung hinzu.

ulidtko
quelle