NAME=sam echo whateverändert den Wert von NAMEin der Shell nicht.
Rici
Antworten:
80
Diese müssen als unterschiedliche Befehle ausgeführt werden, z.
NAME=sam; echo"$NAME"
NAME=sam && echo"$NAME"
Die Erweiterung $NAMEauf leere Zeichenfolge wird von der Shell vor dem Ausführen früher durchgeführt. Wenn echodie NAMEVariable an die echoUmgebung des Befehls übergeben wird, erfolgt die Erweiterung bereits (auf Nullzeichenfolge).
So erzielen Sie das gleiche Ergebnis mit einem Befehl:
Ich habe eine Notiz über hinzugefügt printenv. Hoffe es ist OK, @heemayl
Aaron McDaid
2
Beachten Sie, dass nur der printenvBefehl -based die Semantik des OP-Befehls beibehält : Definieren NAMEals Umgebungsvariable mit Befehlsbereich , die nur der aufgerufene Befehl und seine untergeordneten Prozesse sehen, aber keine nachfolgenden Shell-Befehle. Die anderen Befehle machen etwas ganz anderes: Sie definieren sich NAMEals eine Nur-die-aktuelle-Shell-Exit-Shell-Variable , die alle nachfolgenden Shell- Befehle sehen, aber keine externen Dienstprogramme .
mklement0
13
Um die vorhandenen Antworten mit einer wichtigen Klarstellung zusammenzuführen:
Wie bereits erwähnt, besteht das Problem NAME=sam echo "$NAME"darin, dass $NAMEdie aktuelle Shell sie erweitert, bevor die Zuweisung NAME=samwirksam wird.
Lösungen, die die ursprüngliche Semantik (des (ineffektiven) Lösungsversuchs NAME=sam echo "$NAME") beibehalten :
Verwenden Sie entweder eval[1]
(wie in der Frage selbst) oder printenv(wie von Aaron McDaid zu Heemayls Antwort hinzugefügt ) oder bash -c(aus Ljm Dullaarts Antwort ) in absteigender Reihenfolge der Effizienz:
NAME=sam eval'echo "$NAME"'# use `eval` only if you fully control the command string
NAME=sam printenv NAME
NAME=sam bash -c 'echo "$NAME"'
printenv ist kein POSIX-Dienstprogramm, aber es ist sowohl unter Linux als auch unter macOS / BSD verfügbar.
Mit diesem Aufrufstil ( <var>=<name> cmd ...) wird Folgendes definiert NAME:
als Umgebungsvariable
Dies ist nur für den aufgerufenen Befehl definiert .
Mit anderen Worten: NAMENur für den aufgerufenen Befehl vorhanden und hat keine Auswirkung auf die aktuelle Shell (wenn zuvor keine Variable mit dem Namen NAMEvorhanden war, gibt es danach keine; eine bereits vorhandene NAMEVariable bleibt unverändert).
Die folgenden Lösungen funktionieren sehr unterschiedlich (von Heemayls Antwort ):
NAME=sam; echo"$NAME"
NAME=sam && echo"$NAME"
Während sie dieselbe Ausgabe erzeugen , definieren sie stattdessen:
eine Schale VariableNAME (nur) als eine Umgebungsvariable
Wenn echoein Befehl auf Umgebungsvariablen basieren würde NAME, würde er nicht definiert (oder möglicherweise anders als zuvor definiert).
das lebt nach dem Befehl weiter.
Beachten Sie, dass jede Umgebungsvariable auch als Shell-Variable verfügbar gemacht wird, aber das Gegenteil ist nicht der Fall: Shell-Variablen sind nur für die aktuelle Shell und ihre Subshells sichtbar, nicht jedoch für untergeordnete Prozesse wie externe Dienstprogramme und (nicht bezogene) Skripte (es sei denn, sie sind als Umgebungsvariablen mit exportoder markiert declare -x).
[1] Technisch gesehen bashverstößt POSIX hier (wie es ist zsh): Da evaleine spezielle Shell integriert ist, sollte die vorhergehende NAME=samZuweisung dazu führen, dass die Variable $NAMEnach Abschluss des Befehls im Gültigkeitsbereich bleibt, aber das passiert nicht.
Wenn Sie jedoch bashim POSIX-Kompatibilitätsmodus ausgeführt werden, ist dieser kompatibel. dashund kshsind immer konform.
Die genauen Regeln sind kompliziert und einige Aspekte müssen von den Implementierungen entschieden werden. Siehe auch Befehlssuche und -ausführung .
Außerdem gilt die übliche Haftungsausschluss: Verwenden Sie evalnur bei der Eingabe Sie vollständig kontrollieren oder implizit vertrauen .
wird häufig verwendet, um Umgebungsvariablen für einen bestimmten Prozess festzulegen. Sie müssen jedoch verstehen, welcher Prozess welche Variable erhält und wer sie interpretiert. Als Beispiel mit zwei Muscheln:
a=5
# variable expansion by the current shell:
a=3 bash -c "echo $a"# variable expansion by the second shell:
a=3 bash -c 'echo $a'
Das Ergebnis ist 5 für das erste Echo und 3 für das zweite.
NAME=sam echo whatever
ändert den Wert vonNAME
in der Shell nicht.Antworten:
Diese müssen als unterschiedliche Befehle ausgeführt werden, z.
NAME=sam; echo "$NAME" NAME=sam && echo "$NAME"
Die Erweiterung
$NAME
auf leere Zeichenfolge wird von der Shell vor dem Ausführen früher durchgeführt. Wennecho
dieNAME
Variable an dieecho
Umgebung des Befehls übergeben wird, erfolgt die Erweiterung bereits (auf Nullzeichenfolge).So erzielen Sie das gleiche Ergebnis mit einem Befehl:
quelle
printenv
. Hoffe es ist OK, @heemaylprintenv
Befehl -based die Semantik des OP-Befehls beibehält : DefinierenNAME
als Umgebungsvariable mit Befehlsbereich , die nur der aufgerufene Befehl und seine untergeordneten Prozesse sehen, aber keine nachfolgenden Shell-Befehle. Die anderen Befehle machen etwas ganz anderes: Sie definieren sichNAME
als eine Nur-die-aktuelle-Shell-Exit-Shell-Variable , die alle nachfolgenden Shell- Befehle sehen, aber keine externen Dienstprogramme .Um die vorhandenen Antworten mit einer wichtigen Klarstellung zusammenzuführen:
Wie bereits erwähnt, besteht das Problem
NAME=sam echo "$NAME"
darin, dass$NAME
die aktuelle Shell sie erweitert, bevor die ZuweisungNAME=sam
wirksam wird.Lösungen, die die ursprüngliche Semantik (des (ineffektiven) Lösungsversuchs
NAME=sam echo "$NAME"
) beibehalten :Verwenden Sie entweder
eval
[1] (wie in der Frage selbst) oderprintenv
(wie von Aaron McDaid zu Heemayls Antwort hinzugefügt ) oderbash -c
(aus Ljm Dullaarts Antwort ) in absteigender Reihenfolge der Effizienz:NAME=sam eval 'echo "$NAME"' # use `eval` only if you fully control the command string NAME=sam printenv NAME NAME=sam bash -c 'echo "$NAME"'
printenv
ist kein POSIX-Dienstprogramm, aber es ist sowohl unter Linux als auch unter macOS / BSD verfügbar.Mit diesem Aufrufstil (
<var>=<name> cmd ...
) wird Folgendes definiertNAME
:Mit anderen Worten:
NAME
Nur für den aufgerufenen Befehl vorhanden und hat keine Auswirkung auf die aktuelle Shell (wenn zuvor keine Variable mit dem NamenNAME
vorhanden war, gibt es danach keine; eine bereits vorhandeneNAME
Variable bleibt unverändert).POSIX definiert die Regeln für diese Art von Aufruf in seinem Kapitel Befehlssuche und -ausführung .
Die folgenden Lösungen funktionieren sehr unterschiedlich (von Heemayls Antwort ):
NAME=sam; echo "$NAME" NAME=sam && echo "$NAME"
Während sie dieselbe Ausgabe erzeugen , definieren sie stattdessen:
NAME
(nur) als eine Umgebungsvariableecho
ein Befehl auf Umgebungsvariablen basieren würdeNAME
, würde er nicht definiert (oder möglicherweise anders als zuvor definiert).Beachten Sie, dass jede Umgebungsvariable auch als Shell-Variable verfügbar gemacht wird, aber das Gegenteil ist nicht der Fall: Shell-Variablen sind nur für die aktuelle Shell und ihre Subshells sichtbar, nicht jedoch für untergeordnete Prozesse wie externe Dienstprogramme und (nicht bezogene) Skripte (es sei denn, sie sind als Umgebungsvariablen mit
export
oder markiertdeclare -x
).[1] Technisch gesehen
bash
verstößt POSIX hier (wie es istzsh
): Daeval
eine spezielle Shell integriert ist, sollte die vorhergehendeNAME=sam
Zuweisung dazu führen, dass die Variable$NAME
nach Abschluss des Befehls im Gültigkeitsbereich bleibt, aber das passiert nicht.Wenn Sie jedoch
bash
im POSIX-Kompatibilitätsmodus ausgeführt werden, ist dieser kompatibel.dash
undksh
sind immer konform.Die genauen Regeln sind kompliziert und einige Aspekte müssen von den Implementierungen entschieden werden. Siehe auch Befehlssuche und -ausführung .
Außerdem gilt die übliche Haftungsausschluss: Verwenden Sie
eval
nur bei der Eingabe Sie vollständig kontrollieren oder implizit vertrauen .quelle
Die Syntax
variable=value command
wird häufig verwendet, um Umgebungsvariablen für einen bestimmten Prozess festzulegen. Sie müssen jedoch verstehen, welcher Prozess welche Variable erhält und wer sie interpretiert. Als Beispiel mit zwei Muscheln:
a=5 # variable expansion by the current shell: a=3 bash -c "echo $a" # variable expansion by the second shell: a=3 bash -c 'echo $a'
Das Ergebnis ist 5 für das erste Echo und 3 für das zweite.
quelle
Dies funktioniert auch mit dem Semikolon.
NAME=sam; echo $NAME
quelle