Welche Bereiche können Shell-Variablen haben?

Ich bin gerade auf ein Problem gestoßen, das mir zeigt, dass mir der Umfang der Shell-Variablen nicht klar ist.

Ich habe es versucht Verwenden Sie bundle install, einen Ruby-Befehl, der den Wert von $GEM_HOME verwendet, um seine Arbeit zu erledigen. Ich hatte , aber der Befehl ignorierte diesen Wert, bis ich export wie in export GEM_HOME=/some/path verwendete.

Ich habe gelesen, dass dies die Variable irgendwie „global“ macht (auch bekannt als Umgebungsvariable ), aber ich tue es nicht verstehe was das bedeutet. Ich kenne mich mit Globals in der Programmierung aus, aber nicht mit verschiedenen Programmen.

Da meine Einstellung solcher Variablen nur für die aktuelle Shell-Sitzung gilt, wie würde ich sie beispielsweise für einen daemonisierten Prozess festlegen?

Welche Bereiche können Shell-Variablen haben?

Antwort

Die Prozesse sind als Baum organisiert: Jeder Prozess hat ein eindeutiges übergeordnetes Element, abgesehen von init, das PID ist immer 1 und hat kein übergeordnetes Element.

Die Erstellung eines neuen Prozesses erfolgt im Allgemeinen über ein Paar von fork / execv Systemaufrufe, bei denen die Umgebung des untergeordneten Prozesses eine Kopie des übergeordneten Prozesses ist.

Um eine Variable aus der Shell in die Umgebung einzufügen, müssen Sie export diese Variable verwenden, damit sie für alle untergeordneten Elemente rekursiv sichtbar ist. Beachten Sie jedoch, dass, wenn ein untergeordnetes Element den Wert einer Variablen ändert, der geänderte Wert nur für diese sichtbar ist und alle Prozesse nach dieser Änderung erstellt werden (wie zuvor eine Kopie ) sagte).

Berücksichtigen Sie auch, dass ein untergeordneter Prozess seine Umgebung ändern könnte, beispielsweise auf Standardwerte zurücksetzen könnte, wie dies wahrscheinlich ab login für der Fall ist Beispiel.

Kommentare

  • Ah! OK, lassen Sie ‚ sehen, ob ich das verstehe. Wenn ich in der Shell FOO=bar sage, wird der Wert für den aktuellen Shell-Prozess festgelegt. Wenn ich dann ein Programm wie (bundle install) ausführe, wird ein untergeordneter Prozess erstellt, der ‚ keinen Zugriff auf FOO. Wenn ich jedoch export FOO=bar gesagt hätte, hätte der untergeordnete Prozess (und seine Nachkommen) Zugriff darauf. Einer von ihnen könnte wiederum export FOO=buzz aufrufen, um den Wert für seine Nachkommen zu ändern, oder einfach FOO=buzz, um den Wert nur für sich selbst zu ändern . Ist das ungefähr richtig?
  • @NathanLong Das ‚ ist nicht genau das: In allen modernen Shells wird eine Variable entweder exportiert (und jede Wertänderung auch in der Umgebung von Nachkommen reflektiert) oder nicht exportiert (was bedeutet, dass sich die Variable nicht in der Umgebung befindet). Insbesondere wenn sich die Variable beim Start der Shell bereits in der Umgebung befindet, wird sie exportiert.
  • Ich war ein wenig verwirrt über den Satz „, wenn ein Kind Wenn Sie den Wert einer Variablen ändern, ist der geänderte Wert nur für sie sichtbar, und alle nach dieser Änderung erstellten Prozesse ändern „. Es wäre richtiger zu sagen, dass “ … für ihn sichtbar ist und alle nach dieser Änderung erstellten Nachkommenprozesse “ – der andere Kinder des übergeordneten Prozesses, auch diejenigen, die nach dem untergeordneten Prozess gestartet wurden, sind nicht betroffen.

Antwort

At Zumindest unter ksh und bash können Variablen drei Bereiche, nicht zwei , wie alle verbleibenden Antworten derzeit aussagen.

In Zusätzlich zu den Bereichen für exportierte (dh Umgebungsvariablen) und nicht exportierte Shell-Variablen gibt es einen dritten engeren Bereich für lokale Funktionsvariablen.

In Shell-Funktionen deklarierte Variablen mit der typeset -Token sind nur innerhalb der Funktionen sichtbar, in denen sie deklariert sind, und in (Unter-) Funktionen, die von dort aufgerufen werden.

Diese ksh / bash Code:

# Create a shell script named /tmp/show that displays the scoped variables values. echo "echo [$environment] [$shell] [$local]" > /tmp/show chmod +x /tmp/show # Function local variable declaration function f { typeset local=three echo "in function": . /tmp/show } # Global variable declaration export environment=one # Unexported (i.e. local) variable declaration shell=two # Call the function that creates a function local variable and # display all three variable values from inside the function f # Display the three values from outside the function echo "in shell": . /tmp/show # Display the same values from a subshell echo "in subshell": /tmp/show # Display the same values from a disconnected shell (simulated here by a clean environment start) echo "in other shell" env -i /tmp/show 

erzeugt diese Ausgabe:

in function: [one] [two] [three] in shell: [one] [two] [] in subshell: [one] [] [] in other shell [] [] [] 

Wie Sie sehen können, wird die exportierte Variable an den ersten drei Stellen angezeigt, die nicht exportierten Variablen werden nicht außerhalb der aktuellen Shell angezeigt und die lokale Variable der Funktion hat außerhalb der Funktion selbst keinen Wert. Der letzte Test zeigt überhaupt keine Werte an, da exportierte Variablen nicht von Shells gemeinsam genutzt werden, d. H. Sie können nur vererbt werden und der geerbte Wert kann danach nicht mehr von der übergeordneten Shell beeinflusst werden.

Beachten Sie, dass sich dieses letztere Verhalten erheblich von dem unter Windows unterscheidet, bei dem Sie Systemvariablen verwenden können, die vollständig global sind und von allen Prozessen gemeinsam genutzt werden.

Antwort

Sie sind nach Prozessen geordnet

Die anderen Antwortenden haben mir geholfen zu verstehen, dass es sich bei dem Bereich der Shell-Variablen um -Prozesse handelt und ihre Nachkommen .

Wenn Sie einen Befehl wie ls in die Befehlszeile eingeben, sind Sie tatsächlich Forken eines Prozesses zum Ausführen des Programms ls. Der neue Prozess hat Ihre Shell als übergeordnetes Element.

Jeder Prozess kann seine eigenen „lokalen“ Variablen haben Wird nicht an untergeordnete Prozesse übergeben. Es können auch „Umgebungs“ -Variablen festgelegt werden. Mit export wird eine Umgebungsvariable erstellt. In beiden In diesem Fall sehen nicht verwandte Prozesse (Peers des Originals) die Variable nicht. Wir steuern nur, welcher untergeordnete Prozess ausgeführt wird Esses siehe.

Angenommen, Sie haben eine Bash-Shell, die wir „A“ nennen. Sie geben bash ein , die eine untergeordnete Prozess-Bash-Shell erstellt, die wir „B“ nennen. Alles, was Sie in A export on genannt haben, wird weiterhin in B gesetzt.

In B sagen Sie FOO=b. Eines von zwei Dingen wird passieren:

  • Wenn B (von A) keine Umgebungsvariable mit dem Namen FOO empfangen hat, wird eine lokale Variable erstellt. Kinder von B werden es nicht bekommen (es sei denn, B ruft export auf).
  • Wenn B empfängt (von A) eine Umgebungsvariable mit dem Namen FOO, ändert sie für sich selbst und seine anschließend gegabelten Kinder . Kinder von B sehen den von B zugewiesenen Wert. wirkt sich jedoch überhaupt nicht auf A aus.

Hier ist eine schnelle Demo

FOO=a # set "local" environment variable echo $FOO # "a" bash # forks a child process for the new shell echo $FOO # not set exit # return to original shell echo $FOO # still "a" export FOO # make FOO an environment variable bash # fork a new "child" shell echo $FOO # outputs "a" FOO=b # modifies environment (not local) variable bash # fork "grandchild" shell echo $FOO # outputs "b" exit # back to child shell exit # back to original shell echo $FOO # outputs "a" 

All dies erklärt mein ursprüngliches Problem: Ich habe GEM_HOME in meiner Shell festgelegt, aber als ich anrief bundle install, das einen untergeordneten Prozess erstellt hat. Da ich export nicht verwendet hatte, hat der untergeordnete Prozess die Shell „s GEM_HOME.

Export nicht exportieren

Sie können den Export einer Variablen „aufheben“ – verhindern, dass sie an untergeordnete Elemente übergeben wird -, indem Sie export -n FOO.

export FOO=a # Set environment variable bash # fork a shell echo $FOO # outputs "a" export -n FOO # remove environment var for children bash # fork a shell echo $FOO # Not set exit # back up a level echo $FOO # outputs "a" - still a local variable 

Kommentare

  • Wenn Sie sagen “ Es wird für sich und seine untergeordneten Elemente geändert. “ Sie sollten klarstellen, dass nur untergeordnete Elemente nach der Änderung erstellt wurden wird den geänderten Wert sehen.
  • @enzotib – guter Punkt. Aktualisiert.

Antwort

Die beste Erklärung, die ich zum Exportieren finden kann, ist folgende:

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html

Die in einer Subshell oder untergeordneten Shell festgelegte Variable ist nur für sichtbar die Unterschale, in der es definiert ist. Die exportierte Variable wird tatsächlich als Umgebungsvariable erstellt. Um klar zu sein, führt Ihre bundle install eine eigene Shell aus, die die $GEM_HOME nur dann anzeigt, wenn sie als Variable aka exportiert.

Die Dokumentation zum Variablenbereich finden Sie hier:

http://www.tldp.org/LDP/abs/html/subshells.html

Kommentare

  • Ah, also habe ich den Begriff “ Umgebungsvariable “ für FOO=bar; Sie müssen export um es zu einer zu machen. Frage entsprechend korrigiert.
  • Sehen Sie sich den Link an, den ich hinzugefügt habe.

Antwort

Es gibt erwartungsgemäß eine Hierarchie variabler Bereiche.

Umgebung

Der äußerste Bereich ist die Umgebung. Dies ist der einzige Bereich Wird vom Betriebssystem verwaltet und ist daher für jeden Prozess garantiert vorhanden. Wenn ein Prozess gestartet wird, erhält er eine Kopie der Umgebung des Elternteils, nach der die beiden unabhängig werden: Durch Ändern der Umgebung des Kindes wird die Umgebung des Elternteils nicht geändert, und durch Ändern der Umgebung des Elternteils wird die eines bereits vorhandenen Kindes nicht geändert.

Shell-Variablen

Shells haben ihre eigene Vorstellung von Variablen. Hier wird es etwas verwirrend.

Wenn Sie einer Variablen in einer Shell einen Wert zuweisen und diese Variable bereits in der Umgebung vorhanden ist, erhält die Umgebungsvariable den neuen Wert. Befindet sich die Variable jedoch noch nicht in der Umgebung, wird sie zu einer Shell -Variablen. Shell-Variablen existieren nur innerhalb des Shell-Prozesses, ähnlich wie Ruby-Variablen nur in einem Ruby-Skript existieren. Sie werden niemals von untergeordneten Prozessen geerbt.

Hier kommt das Schlüsselwort export ins Spiel. Es kopiert eine Shell-Variable in die Umgebung des Shell-Prozesses, sodass untergeordnete Prozesse erben können.

Lokale Variablen

Lokale Variablen sind Shell-Variablen, die auf die sie enthaltenden Codeblöcke beschränkt sind. Sie deklarieren lokale Variablen mit dem Schlüsselwort typeset (portabel) oder local oder declare (Bash) ). Wie andere Shell-Variablen werden lokale Variablen nicht von untergeordneten Prozessen geerbt. Auch lokale Variablen können nicht exportiert werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.