Betrachten Sie diesen Ausschnitt:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
Hier habe ich $SOMEVAR
in AAA
der ersten Zeile eingestellt - und wenn ich es in der zweiten Zeile wiedergebe, erhalte ich den AAA
Inhalt wie erwartet.
Aber dann, wenn ich versuche, die Variable in derselben Befehlszeile wie die echo
folgende anzugeben :
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... Ich bekomme nicht BBB
wie erwartet - ich bekomme den alten Wert ( AAA
).
Sollen die Dinge so sein? Wenn ja, wie kommt es, dass Sie Variablen wie angeben LD_PRELOAD=/... program args ...
und es funktionieren lassen können? Was vermisse ich?
bash
environment-variables
echo
sdaau
quelle
quelle
LD_PRELOAD
Arbeiten sind , dass der Variable in dem Programm gesetzt Umgebung - nicht auf seiner Kommandozeile.Antworten:
Was Sie sehen, ist das erwartete Verhalten. Das Problem besteht darin, dass die übergeordnete Shell
$SOMEVAR
in der Befehlszeile ausgewertet wird , bevor der Befehl mit der geänderten Umgebung aufgerufen wird. Sie müssen die Auswertung$SOMEVAR
aufgeschoben erhalten, bis die Umgebung eingestellt ist.Ihre unmittelbaren Optionen umfassen:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.Beide verwenden einfache Anführungszeichen, um zu verhindern, dass die übergeordnete Shell ausgewertet wird
$SOMEVAR
. Es wird erst ausgewertet, nachdem es in der Umgebung festgelegt wurde (vorübergehend für die Dauer des einzelnen Befehls).Eine andere Möglichkeit ist die Verwendung der Sub-Shell-Notation (wie auch von Marcus Kuhn in seiner Antwort vorgeschlagen ):
Die Variable wird nur in der Unterschale festgelegt
quelle
Das Problem, überarbeitet
Ehrlich gesagt ist das Handbuch in diesem Punkt verwirrend. Das GNU Bash Handbuch sagt:
Wenn Sie den Satz wirklich analysieren, heißt es, dass die Umgebung für den Befehl / die Funktion geändert wird, nicht jedoch die Umgebung für den übergeordneten Prozess. Das wird also funktionieren:
weil die Umgebung für den Befehl env vor seiner Ausführung geändert wurde. Dies wird jedoch nicht funktionieren:
aufgrund dessen, wann die Parametererweiterung von der Shell durchgeführt wird.
Dolmetscherschritte
Ein weiterer Teil des Problems besteht darin, dass Bash diese Schritte für seinen Interpreter definiert:
Was hier passiert, ist, dass Buildins keine eigene Ausführungsumgebung erhalten, sodass sie die geänderte Umgebung nie sehen. Darüber hinaus einfache Befehle (zB / bin / echo) Sie erhalten eine modifizierte ennvironment (weshalb das env Beispiel arbeitete) , aber die Shell - Erweiterung ist in der stattfindet aktuellen Umgebung in Schritt # 4.
Mit anderen Worten, Sie übergeben 'aaa $ TESTVAR ccc' nicht an / bin / echo; Sie übergeben die interpolierte Zeichenfolge (wie in der aktuellen Umgebung erweitert) an / bin / echo. In diesem Fall übergeben Sie einfach 'aaa ccc' an den Befehl , da die aktuelle Umgebung kein TESTVAR enthält .
Zusammenfassung
Die Dokumentation könnte viel klarer sein. Gut, dass es einen Stapelüberlauf gibt!
Siehe auch
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
quelle
FOO=foo eval 'echo $FOO'
drucktfoo
wie erwartet. Dies bedeutet, dass Sie Dinge wie tun könnenIFS="..." read ...
.Verwenden Sie, um das zu erreichen, was Sie möchten
Grund:
Sie müssen die Zuweisung durch Semikolon oder neue Zeile vom nächsten Befehl trennen, andernfalls wird sie nicht ausgeführt, bevor die Parametererweiterung für den nächsten Befehl (Echo) erfolgt.
Sie müssen die Zuweisung in einer Subshell- Umgebung vornehmen , um sicherzustellen, dass sie nicht über die aktuelle Zeile hinaus bestehen bleibt.
Diese Lösung ist kürzer, übersichtlicher und effizienter als einige der anderen vorgeschlagenen, insbesondere wird kein neuer Prozess erstellt.
quelle
(export SOMEVAR=BBB; python -c "from os import getenv; print getenv('SOMEVAR')")
SOMEVAR=BBB python -c "from os import getenv; print getenv('SOMEVAR')"
Der Grund ist, dass dies eine Umgebungsvariable für eine Zeile festlegt. Aber
echo
macht nicht die Erweiterung,bash
tut. Daher wird Ihre Variable tatsächlich erweitert, bevor der Befehl ausgeführt wird, obwohl sieSOME_VAR
sichBBB
im Kontext des Echo-Befehls befindet.Um den Effekt zu sehen, können Sie Folgendes tun:
Hier wird die Variable erst erweitert, wenn der untergeordnete Prozess ausgeführt wird, sodass Sie den aktualisierten Wert sehen. Wenn Sie
SOME_VARIABLE
die übergeordnete Shell erneut überprüfen , ist diesAAA
erwartungsgemäß weiterhin der Fall.quelle
Benutze einen ; Anweisungen zu trennen, die sich in derselben Zeile befinden.
quelle
LD_PRELOAD
und so kann man vor einer ausführbaren Datei ohne Semikolon arbeiten ... Nochmals vielen Dank - Prost!Hier ist eine Alternative:
quelle
&&
oder;
trennen, bleibt die Zuweisung bestehen, was nicht das gewünschte Verhalten von OP ist. Markus Kuhn hat die richtige Version dieser Antwort.