Was genau ist eine Umgebungsvariable?

42

Ich weiß, dass VARIABLE=valueeine Umgebungsvariable erstellt und export VARIABLE=valuefür Prozesse verfügbar gemacht wird, die von der aktuellen Shell erstellt wurden. envzeigt die aktuellen Umgebungsvariablen an, aber wo leben sie? Was umfasst eine Umgebungsvariable (oder eigentlich eine Umgebung )?

Matt
quelle

Antworten:

29

Eine Umgebung ist nicht so magisch, wie es scheint. Die Shell speichert es im Speicher und übergibt es an den execve()Systemaufruf. Der untergeordnete Prozess erbt ihn als aufgerufenen Array-Zeiger environ. Aus der execveManpage:

ZUSAMMENFASSUNG

   #include <unistd.h>

   int execve(const char *filename, char *const argv[],
              char *const envp[]);

argvist ein Array von Argumenten, die an das neue Programm übergeben werden.
Gemäß der Konvention sollte die erste dieser Zeichenfolgen den Dateinamen enthalten, der der ausgeführten Datei zugeordnet ist. envpist ein Array von Strings, üblicherweise mit der Form key = value, die als Umgebung an das neue Programm übergeben werden.

Die environ(7)Manpage bietet auch einige Einblicke:

ZUSAMMENFASSUNG

   extern char **environ;

BESCHREIBUNG

Die Variable environzeigt auf ein Array von Zeigern auf Zeichenfolgen, die als "Umgebung" bezeichnet werden. Der letzte Zeiger in diesem Array hat den Wert NULL. (Diese Variable muss im Benutzerprogramm deklariert werden, wird jedoch in der Header-Datei deklariert, <unistd.h>falls die Header-Dateien aus libc4 oder libc5 stammen und falls sie aus glibc stammen und _GNU_SOURCE definiert wurde.) Dieses Array von Strings wird für bereitgestellt der Prozess durch den exec (3) -Aufruf, der den Prozess gestartet hat.

Beide GNU-Hilfeseiten stimmen mit der POSIX-Spezifikation überein

Jordanien
quelle
4
+1 Es ist wahrscheinlich erwähnenswert, dass einige exec(3)Familienmitglieder (dh diejenigen, die nicht mit exec * v übereinstimmen) die Umgebungsbedingungen nicht erfüllen.
msw
5
Beachten Sie, dass es sich nicht um untergeordnete Prozesse handelt (untergeordnete Prozesse erben den gesamten Speicher des übergeordneten Prozesses), sondern um ausgeführte Programme (im selben Prozess). Es ist also eine andere Möglichkeit, Daten über einen Systemaufruf von execve () weiterzuleiten (der sonst den Speicher löscht) des Prozesses).
Stéphane Chazelas
@msw: Es sind die exec*eVarianten, die explizit ein env übergeben, anstatt implizit die environglobale Variable zu verwenden. Das vbedeutet "vector" und bezieht sich auf die als Array übergebenen Befehlszeilenargumente (anstelle einer "list" (Funktion mit variabler Länge)) und execveist ein Systemaufruf. Alle anderen exec*Funktionen sind libc-Wrapper dafür.
Peter Cordes
19

Sie haben es ein wenig falsch verstanden: SOME_NAME=valueErstellt eine Shell-Variable (in den meisten Shells). export SOME_NAME=valueErstellt eine Umgebungsvariable. Die meisten Unix / Linux / * BSD-Shells verwenden beim Zugriff auf Umgebungsvariablen und Shell-Variablen die gleiche Syntax.

Im weiteren Sinne ist eine "Umgebung" nur die Information, die mit der Programmausführung einhergeht. In C - Programmen können Sie den Prozess - ID mit einem finden getpid()Anruf, in einem Shell - Programm würden verwenden Sie einen variablen Zugang: $$. Die Prozess-ID ist nur ein Teil der Programmumgebung. Ich glaube, der Begriff "Umgebung" kommt von einigen der theoretischeren Informatik-Themen, wie der Modellierung der Programmausführung. Modelle der Programmausführung haben eine Umgebung, "die die Assoziationen zwischen Variablen und ihren Werten enthält".

Und diese letztere, stärkere Definition ist, was eine "Umgebung" für Unix / Linux / * BSD-Shells ist: eine Assoziation zwischen Namen ("Variablen") und ihren Werten. Bei den meisten Unix-Shells handelt es sich bei den Werten um Zeichenfolgen, obwohl dies nicht mehr so ​​genau wie früher der Fall ist. Ksh, Zsh und Bash haben heutzutage alle Variablen eingegeben. Sogar Shell-Funktionsdefinitionen können exportiert werden.

Die Verwendung einer von einfachen Shell-Variablen getrennten Umgebung umfasst die fork/execMethode zum Starten eines neuen Prozesses, den alle Unix-Benutzer verwenden. Wenn Sie exportein Name / Wert-Paar haben, ist dieses Name / Wert-Paar in der Umgebung neuer ausführbarer Dateien vorhanden, die von der Shell mit einem execve(2)Systemaufruf gestartet werden (normalerweise nach a fork(2), außer wenn der execShell-Befehl verwendet wurde).

Im Anschluss an execve()hat die main()Funktion new binary ihre Befehlszeilenargumente, die Umgebung (gespeichert als NULL-terminiertes Array von Zeigern auf var=valueZeichenfolgen, siehe environ(7)Manpage). Ein anderer geerbter Status umfasst ulimitEinstellungen, das aktuelle Arbeitsverzeichnis und alle geöffneten Dateideskriptoren, für die der execve()Aufrufer FD_CLOEXEC nicht festgelegt hat. Der aktuelle Status des Tty (Echo aktiviert, Raw-Modus usw.) kann auch als Teil des Ausführungsstatus betrachtet werden, der von einem neu erstellten execProzess geerbt wurde .

In der bashBeschreibung der Ausführungsumgebung im Handbuch finden Sie Informationen zu einfachen Befehlen (außer integrierten oder Shell-Funktionen).

Die Unix-Umgebung unterscheidet sich zumindest von einigen anderen Betriebssystemen: VMS-"Lexika" konnten von einem untergeordneten Prozess geändert werden, und diese Änderung war im übergeordneten Prozess sichtbar. Ein VMS cdin einem untergeordneten Prozess wirkt sich auf das Arbeitsverzeichnis des übergeordneten Prozesses aus. Zumindest unter bestimmten Umständen, und mein Gedächtnis kann mich verfehlen.

Einige Umgebungsvariablen sind gut bekannt $HOME, $PATH, $LD_LIBRARY_PATHund andere. Einige sind für ein bestimmtes Programmiersystem üblich, sodass eine übergeordnete Shell sehr viele spezielle Informationen an ein Programm weitergeben kann, z. B. ein bestimmtes temporäres Verzeichnis oder eine Benutzer-ID und ein Kennwort, die nicht in angezeigt werden ps -ef. Einfache CGI-Programme erben beispielsweise über Umgebungsvariablen viele Informationen vom Webserver.

Bruce Ediger
quelle
1
Es scheint noch etwas komplizierter zu sein. Zumindest in Bash SOME_NAME=value commandwird die Umgebungsvariable SOME_NAME für diesen Befehlsaufruf festgelegt. Verwirrenderweise scheint die gleichnamige Shell-Variable nicht gesetzt zu werden.
Samuel Edwin Ward
2
Genauer gesagt, werden Umgebungsvariablen nicht vererbt, sondern explizit von einer Shell an von ihr erzeugte Programme übergeben.
msw
2
@SamuelEdwinWard Der Grund, warum Sie SOME_NAME=value commandsich wider Erwarten verhalten, ist eine spezielle Syntax, die bedeutet, dass Sie der an den Befehl übergebenen Umgebung SOME_NAME hinzufügen, die Variablen dieser Shell jedoch nicht anderweitig ändern.
msw
1
Faszinierend, die Verbindung zur Lambda-Rechnung / Funktionsprogrammierung. Das ist eine interessante Verbindung, die sehr viel Sinn macht.
Matt
1
Einiges davon ist nicht ganz richtig. Zum Beispiel Subshells sind Teilprozesse und müssen fork()ed, aber sie tun erhalten (Kopien) Shell - Variablen.
Ruakh
7

Umgebungsvariablen in ihrer ursprünglichsten Form sind nur eine Reihe von Name / Wert-Paaren. Wie in der bash-Manpage ( man 1 bash) im Abschnitt UMWELT beschrieben:

   When  a  program  is invoked it is given an array of strings called the
   environment.   This  is  a  list  of  name-value  pairs,  of  the  form
   name=value.

   The  shell  provides  several  ways  to manipulate the environment.  On
   invocation, the shell scans its own environment and creates a parameter
   for  each name found, automatically marking it for export to child pro-
   cesses.  Executed commands inherit the  environment.

In der Praxis können Sie damit ein Verhalten definieren, das für Programme, die über die aktuelle Shell aufgerufen werden, freigegeben oder eindeutig ist. Wenn Sie beispielsweise crontaboder verwenden visudo, können Sie die EDITORUmgebungsvariable definieren, um einen anderen Editor als den zu definieren, den Ihr System standardmäßig verwenden würde. Das Gleiche gilt für Dinge wie den manBefehl, mit dem in Ihrer PAGERUmgebung ermittelt wird, mit welchem ​​Pager-Programm die Ausgabe der Manpage angezeigt werden soll.

Sehr viele Unix-Befehle lesen die Umgebung und abhängig davon, was dort eingestellt ist, ändern sie ihre Ausgabe / Verarbeitung / Aktion. Einige werden geteilt, andere sind programmspezifisch. Die meisten Manpages enthalten Informationen darüber, wie sich die Umgebungsvariable auf das beschriebene Programm auswirkt.

Andere praktische Abbildungen beziehen sich beispielsweise auf Systeme mit mehreren Oracle-Installationen auf derselben Plattform. Durch die Einstellung ORACLE_HOMEwird die gesamte Suite der Oracle-Befehle (wie von Ihrer PATHUmgebungsvariablen geladen ) aus diesem Verzeichnis der obersten Ebene abgerufen. Das gleiche gilt für andere Programme wie Java mit seiner JAVA_HOMEUmgebungsvariablen.

Bash selbst hat viele Umgebungsvariablen, die das Verhalten einer Reihe von Dingen wie Verlauf ( HISTSIZE, HISTFILEusw.), Bildschirmgröße ( COLUMNS), Gebietsschema ( FIGNORE, GLOBIGNORE) und Zeichencodierung / -decodierung ( LANG, LC_*), Eingabeaufforderung ( PS1.. PS4) und ändern können usw. (suche erneut das Wissen von der Bash-Manpage).

Sie können auch Skripte / Programme schreiben, die Ihre eigenen benutzerdefinierten Umgebungsvariablen verwenden (um Einstellungen zu übergeben oder Funktionen zu ändern).

Drav Sloan
quelle
0

"Umgebungsvariablen" sind dynamisch benannte Werte, die sich auf das Verhalten von Prozessen auf einem Computer auswirken können.

Sie sind Teil der Betriebsumgebung, in der ein Prozess ausgeführt wird. Beispielsweise kann ein ausgeführter Prozess den Wert der TEMP-Umgebungsvariablen abfragen, um einen geeigneten Speicherort für temporäre Dateien zu ermitteln, oder die Variable HOME oder USERPROFILE, um die Verzeichnisstruktur des Benutzers zu ermitteln, der den Prozess ausführt.

Weitere Informationen hier → http://en.wikipedia.org/wiki/Environment_variable .

Alles, was Sie über Umgebungsvariablen wissen möchten ... ↑

SoCalDiegoRob
quelle
1
Obwohl es unwahrscheinlich ist, dass diese Links verschwinden, ist es besser, die Frage hier mit relevantem Text zu beantworten und den Link als Ergänzung für Sicherungsinformationen bereitzustellen.
Anthon
@Anthon Ich glaube, Sie sind richtig und ich werde die Änderungen vornehmen, sobald ich kann ... Vielen Dank für den Rat ...
SoCalDiegoRob
-1

Für diese Antwort sind einige Kenntnisse und Erfahrungen im Umgang mit Shell-Skripten mit den Begriffen Variable, Wert, Variablensubstitution, Eingabeaufforderung, Echo, Kernel, Shell, Dienstprogramm, Sitzung und Prozess erforderlich.

Eine Umgebungsvariable (envar) ist ein Satz global definierter Variablen, die das Verhalten eines bestimmten Prozesses auf dem Betriebssystem eines Computers beeinflussen können.

1. Eine beispielhafte Einführung:

Wir ersetzen Envars durch a $und Großbuchstaben . Zum Beispiel: $PS1.

Wir können eine Envar folgendermaßen drucken:

echo $PS1

$PS1Enthält den Wert der Unix-Eingabeaufforderung. Sagen wir, seine nativen Werte sind \u \w $.

  • \u steht für (aktuellen) Benutzer,
  • \w steht für Arbeitsverzeichnis,
  • $ ist die Eingabeaufforderung zu begrenzen.

Also, wenn wir tun: echo $PS1Wir sehen die Werte \u, \wund das Dollarzeichen am Ende.

Wir könnten das Unix-Verhalten in diesem Kontext ändern, wenn wir die Werte dieser envar ändern. Zum Beispiel:

PS1="\w >"

Nun sieht die Eingabeaufforderung so aus (vorausgesetzt, das Arbeitsverzeichnis heißt "John"):

John >

Auf die gleiche Weise, die wir tun könnten PS1="Hello, I'm your prompt >", werden wir echo $PS1bringen:

Hello, I'm your prompt >

In Bash 4.xx können wir mit dem envBefehl ALLE Envars im System drucken . Ich schlage vor, envim Terminal auszuführen und mir die Ausgabe anzuschauen.

2. Wie werden diese Daten angezeigt und bearbeitet:

Im Terminal einer Sitzung können wir die mit Bash gelieferten Envars anpassen.

Die oben genannten Änderungen sind in der Regel vorübergehend und aus folgenden Gründen:

Jede Sitzung (die keine Untersitzung ist) ist eindeutig, und mehrere Prozesse können gleichzeitig ausgeführt werden (jeder mit einem eigenen Satz von Envars). In der Regel erfolgt jedoch eine Vererbung von Sitzung 0 zu Sitzung 1 und höher.

Änderungen, die wir an einem Prozess vornehmen, sind einzigartig und werden abgebrochen, wenn wir ihn schließen, ohne ihn auf irgendeine Weise zu speichern.

Wie können wir diese Änderungen speichern:

Abhängig vom ausgewählten Bereich gibt es verschiedene Möglichkeiten zum Speichern von envar-Änderungen. Hier sind verschiedene Bereiche (Ebenen) für solche Änderungen:

  • Prozessebene: Die Envars sind nur für Programme in der aktuellen Sitzung verfügbar.
  • Exportstufe: Die Envars sind für Programme in der aktuellen Sitzung oder allen ihren Untersitzungen verfügbar .
  • Globale Ebene: Die Änderungen werden für alle Sitzungen (primäre und alle Subs) gespeichert.

Wo werden envar-Daten gespeichert:

Unix besteht aus drei Hauptschichten: Kernel, Shell und Dienstprogramme. AFAIK Jede Shell hat ihre eigenen Envars, die hauptsächlich oder ausschließlich in der Shell erstellt werden.

Der spezifische Ort, an dem diese global geändert werden müssen, ist normalerweise, /etc/profileobwohl wir dies .bashrcnatürlich auch tun können .

3. Neue Envars erstellen:

Wir können neue Envars erschaffen und hier ist ein Weg; Ab Bash 4.xx gibt es keinen nativen Enavar-Namen MESSAGE(wie gesagt, Envars werden normalerweise in Großbuchstaben geschrieben).

MESSAGE="Hello world!"

wird es für uns erstellen, und jetzt, wenn wir Echo eingeben $MESSAGE, bekommen wir hello world!.

Wenn wir bashin unserer aktuellen Arbeitssitzung (Fenster) ausführen , würden wir eine neue Bash-Untersitzung starten und werden nicht mehr im ursprünglichen Prozess arbeiten, es sei denn, wir führen aus exit.

Hinweis: In Betriebssystemen mit einem Terminalemulator (wie dem Ubuntu-Desktop) wird eine Untersitzung normalerweise im selben Fenster ausgeführt, eine neue Sitzung in einem anderen Fenster ist jedoch keine Untersitzung der vorhandenen Sitzung (dies ist ein benachbarter Prozess). .

Hinweis: Verwenden Sie keine Sonderzeichen in envar-Werten wie! oder sie werden nicht gespeichert.

Exportieren der Envar aus der ursprünglichen Sitzung in alle Untersitzungen:

Wir können die in der ersten Sitzung erstellte envar weiterhin verwenden, auch in der zweiten Sitzung, ohne sie in den conf-Dateien auf Benutzer- oder globaler Ebene zu registrieren (siehe folgende Daten). So geht's:

Gehen Sie zur ursprünglichen Sitzung (ob im aktuellen oder in einem anderen Fenster) und führen Sie Folgendes aus:

export MESSAGE

Verwenden Sie beim Exportieren kein $Zeichen.

Es wird jetzt in alle Untersitzungen exportiert. Wenn Sie echo $MESSAGEeine Untersitzung durchführen, egal ob von Ihrem oder einem anderen Benutzer, wird diese gedruckt.

Beachten Sie, dass interne Shell-Variablen, wie z. B., PS1nicht exportiert werden sollten. Wenn Sie sie jedoch aus einem beliebigen Grund exportieren möchten und sie nicht angezeigt werden, führen Sie sie nicht bashnach export, sondern nach dem Export aus bash –norc.

4. Die $ PATH-Envar:

$PATH ist das envar, das Benutzer normalerweise am meisten ändern.

Wenn wir echo $PATH, werden wir diesen Stream sehen:

/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Die gedruckten Werte dieser Variable werden dort durch Doppelpunkte (:) getrennt, aber hier ist eine möglicherweise bequemere Möglichkeit (dies sind die gleichen Werte):

/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games

Dies sind Verzeichnisse, nach denen gesucht werden muss, wenn ein Dienstprogramm ausgeführt wird.

Wenn Sie ausführen which echo, erhalten Sie den Speicherort der Datei. Beispielsweise wird möglicherweise festgestellt, dass sie in vorhanden ist /bin/echo.

Basierend darauf müssen wir nicht echo envar eingeben, um die Werte des evnar anzuzeigen. Wir können auch:

/bin/echo $ENVAR

Die envar wird weiterhin ausgeführt, zum Beispiel:

/bin/echo $HOME

Gibt uns

/home/User || /root

Genauso wie:

echo $HOME

Gibt uns

/home/User || /root

Hinweis: $HOMEwird als abgekürzt ~.

Die System- $ PATH-Beziehungen und eine mögliche Benutzerinteraktion:

Wenn Sie in Bash 4.xx ein Dienstprogramm ohne vollständigen Pfad verwenden, verwendet das System alle sechs oben genannten Werte der $PATHenvar. Es beginnt also /user/local/binmit dem gesamten Inhalt, der nach der echoausführbaren Datei sucht .

In diesem Fall hört es bei auf /bin/echo, in welchem ​​Fall sich die ausführbare Datei befindet.

Daher besteht der Hauptgrund, warum wir die $PATHenvar anpassen könnten, darin, ausführbare Dateien zu installieren, die keinem ihrer nativen Werte entsprechen.

Nachdem wir solche ausführbaren Dateien installiert haben, sollten wir ihren $PATHWert entsprechend festlegen und dann in der Lage sein, mit ihnen zu arbeiten.

5. Anhang - erweitern $PATH:

Wir können export $PATHUntersitzungen (einschließlich Bash-Erweiterungen wie WP-CLI für WordPress oder Drush für Drupal) auf folgende Weise bashen:

export PATH="/home/John:$PATH"

Dies wird einen neuen Wert hinzufügen /home/Johnzu $PATH, und dann direkt danach, wird es keine nativen Werte (rechts hinter dem Doppelpunkt) annektiert, die unter der Syntax gespeichert werden $PATH.

Eine solche dauerhafte Änderung kann im entsprechenden Skript normalerweise unter /etc/profileund unter dem Namen vorgenommen werden .bashrc.

JohnDoea
quelle
3
Diese Antwort ist sehr falsch: Zusammenführen von Sitzungen und Prozessen, Warnung vor !einem nicht funktionierenden Wert einer Umgebungsvariablen, der sich direkt unter einem Beispiel befindet, das dessen Funktion zeigt, eine falsche Vorstellung von Untersitzungen, ziemlich bizarre Ratschläge, was zu tun ist nach dem Exportieren einer Shell-Variablen und einer falschen Vorstellung von globalen Umgebungsvariablen.
JdeBP
warning about ! in an environment variable value not working that is right below an example showing it working? Bitte zum Beispiel.
JohnDoea
quite bizarre advice about what to do after exporting a shell variable, was genau meinst du?
JohnDoea
false notion of global environment variables, was genau meinst du?
JohnDoea