Ich bin daran interessiert, Umgebungsvariablen einer Shell-Instanz von einer anderen zu setzen. Also habe ich beschlossen, etwas zu recherchieren. Nach der Lektüre eine Reihe von Fragen über das ich beschlossen , es zu testen.
Ich habe zwei Muscheln A und B (PID 420) hervorgebracht, die beide laufen zsh
. Von der Shell AI lief folgendes.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
Aus Shell B kann ich beim Ausführen env
sehen, dass die Variable FOO tatsächlich mit dem Wert bar gesetzt ist. Dies lässt mich denken, dass FOO in der Umgebung von Shell B erfolgreich initialisiert wurde. Wenn ich jedoch versuche, FOO zu drucken, erhalte ich eine leere Zeile, was bedeutet, dass es nicht gesetzt ist. Für mich scheint es hier einen Widerspruch zu geben.
Dies wurde sowohl auf meinem eigenen Arch GNU / Linux-System als auch auf einer Ubuntu-VM getestet. Ich habe dies auch dort getestet, bash
wo die Variable nicht einmal in env angezeigt wurde. Dies ist zwar für mich enttäuschend, aber sinnvoll, wenn die Shell beim Spawn eine Kopie ihrer Umgebung zwischenspeichert und nur diese verwendet (was in einer der verknüpften Fragen vorgeschlagen wurde). Dies antwortet immer noch nicht, warum zsh
die Variable angezeigt werden kann.
Warum ist die Ausgabe von echo $FOO
leer?
BEARBEITEN
Nach der Eingabe in den Kommentaren habe ich beschlossen, ein bisschen mehr zu testen. Die Ergebnisse sind in den folgenden Tabellen aufgeführt. In der ersten Spalte befindet sich die Shell, in die die FOO
Variable eingefügt wurde. Die erste Zeile enthält den Befehl, dessen Ausgabe darunter angezeigt wird. Die Variable FOO
wurde injiziert mit : sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Die für zsh: spezifischen Befehle zsh -c '...'
wurden ebenfalls mit bash getestet. Die Ergebnisse waren identisch, ihre Ausgabe wurde der Kürze halber weggelassen.
Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Das Obige scheint zu implizieren, dass die Ergebnisse verteilungsunabhängig sind. Dies sagt mir nicht viel mehr als zsh
und bash
behandelt die Einstellung von Variablen anders. Darüber hinaus export FOO
hat sich in diesem Zusammenhang je nach Shell ein sehr unterschiedliches Verhalten. Hoffentlich können diese Tests jemand anderem etwas klar machen.
zsh -c 'echo $FOO'
stattdessen ein (verwenden Sie einfache Anführungszeichen!)? Kannst du es dann sehen?env
) sehen jedoch die geänderte Umgebung.zsh
in GDB sie nicht als Shell-Variable sichtbar macht, sondern dazu führt, dass sie an untergeordnete Prozesse (as) weitergegeben wird Sie haben beobachtet), während das Festlegen von eins für es als Shell-Variable sichtbarbash
macht , aber nicht dazu führt, dass es an untergeordnete Prozesse weitergegeben wird! Es sieht so aus, als ob zsh und bash unterschiedliche Strategien zum Verwalten von Variablen verwenden, wobei zsh Nicht-Umgebungsvariablen verfolgt und bash alles in seiner Umgebung speichert, was beim Starten eines (Nicht-Subshell-) Kindes bereinigt wird.export FOO
inbash
?Antworten:
Die meisten Schalen verwenden Sie nicht die
getenv()
/setenv()
/putenv()
API.Beim Start erstellen sie Shell-Variablen für jede Umgebungsvariable. Diese werden in internen Strukturen gespeichert, die andere Informationen enthalten müssen, z. B. ob die Variable exportiert wird, schreibgeschützt ... Sie können die libc's
environ
dafür nicht verwenden .Auf ähnliche Weise und aus diesem Grund werden sie nicht verwenden
execlp()
,execvp()
um Befehle auszuführen , aber der Anrufexecve()
Systemaufruf direkt, Berechnen desenvp[]
Array basierend auf der Liste ihrer exportierten Variablen.In Ihrem
gdb
müssen Sie also einen Eintrag zu der internen Variablentabelle der Shells hinzufügen oder möglicherweise die richtige Funktion aufrufen, mit der einexport VAR=value
Code interpretiert wird , mit dem diese Tabelle selbst aktualisiert werden kann.Wie, warum Sie sehen einen Unterschied zwischen
bash
und ,zsh
wenn Sie anrufensetenv()
ingdb
vermute ich , das ist , weil Sie anrufen ,setenv()
bevor der Shell initialisiert, zum Beispiel beim Betretenmain()
.Sie werden feststellen, dass
bash
'smain()
istint main(int argc, char* argv[], char* envp[])
(undbash
Variablen aus diesen env-Variablen zuordnetenvp[]
), währendzsh
' s istint main(int argc, char* argv[])
und stattdessenzsh
die Variablenenviron
abruft.setenv()
ändert sichenviron
, kann aber nicht direkt geändert werdenenvp[]
(schreibgeschützt auf mehreren Systemen sowie die Zeichenfolgen, auf die diese Zeiger verweisen).In jedem Fall wäre die
environ
Verwendung nach dem Lesen der Shell beim Startsetenv()
unwirksam, da die Shell danach nicht mehr verwendetenviron
(odergetenv()
).quelle