Die Grundidee ist , dass die VAR=VALUE some-command
Sätze VAR
auf die VALUE
für die Ausführung von , some-command
wenn some-command
ein externer Befehl, und es wird nicht mehr Phantasie als das. Wenn Sie diese Intuition mit etwas Wissen über die Funktionsweise einer Shell kombinieren, sollten Sie in den meisten Fällen die richtige Antwort finden. Die POSIX-Referenz lautet "Einfache Befehle" im Kapitel "Shell Command Language" .
Wenn some-command
es sich um einen externen Befehl handelt , VAR=VALUE some-command
entspricht dies env VAR=VALUE some-command
. VAR
wird in die Umgebung von exportiert some-command
, und sein Wert (oder das Fehlen eines Werts) in der Shell ändert sich nicht.
Wenn some-command
es sich um eine Funktion handelt , VAR=VALUE some-command
ist dies äquivalent zu VAR=VALUE; some-command
, dh die Zuweisung bleibt bestehen, nachdem die Funktion zurückgegeben wurde, und die Variable wird nicht in die Umgebung exportiert. Der Grund dafür hängt mit dem Design der Bourne-Shell (und später mit der Abwärtskompatibilität) zusammen: Sie hatte keine Möglichkeit, Variablenwerte um die Ausführung einer Funktion herum zu speichern und wiederherzustellen. Das Nichtexportieren der Variablen ist sinnvoll, da eine Funktion in der Shell selbst ausgeführt wird. Ksh (einschließlich ATT ksh93 und pdksh / mksh), bash und zsh implementieren jedoch das nützlichere Verhalten, wenn VAR
es nur während der Ausführung der Funktion festgelegt wird (es wird auch exportiert). In ksh geschieht dies, wenn die Funktion mit der ksh-Syntax definiert istfunction NAME …
nicht, wenn es mit der Standardsyntax definiert ist NAME ()
. In Bash wird dies nur im Bash-Modus durchgeführt, nicht im POSIX-Modus (wenn mit ausgeführt POSIXLY_CORRECT=1
). In zsh geschieht dies, wenn die posix_builtins
Option nicht gesetzt ist. Diese Option ist standardmäßig nicht aktiviert, wird jedoch von emulate sh
oder aktiviert emulate ksh
.
Wenn some-command
es sich um eine integrierte Funktion handelt, hängt das Verhalten vom Typ der integrierten Funktion ab. Spezielle Builtins verhalten sich wie Funktionen. Spezielle integrierte Funktionen müssen in der Shell implementiert werden, da sie die Status-Shell beeinflussen (z. B. den break
Kontrollfluss cd
beeinflussen, das aktuelle Verzeichnis set
beeinflussen, Positionsparameter und -optionen beeinflussen…). Andere eingebaute Funktionen dienen nur der Leistung und der Benutzerfreundlichkeit (meistens - z. B. kann die Bash-Funktion printf -v
nur von einer eingebauten Funktion implementiert werden) und verhalten sich wie externe Befehle.
Die Zuweisung erfolgt nach der Alias-Erweiterung. Wenn some-command
es sich also um einen Alias handelt , erweitern Sie ihn zuerst, um herauszufinden, was passiert.
Beachten Sie, dass die Zuweisung in allen Fällen ausgeführt wird, nachdem die Befehlszeile analysiert wurde, einschließlich der Variablenersetzung in der Befehlszeile. Also var=a; var=b echo $var
druckt a
, weil $var
ausgewertet wird, bevor die Zuordnung erfolgt. Und IFS=. printf "%s\n" $var
nutzt somit den alten IFS
Wert zum Teilen $var
.
Ich habe alle Arten von Befehlen behandelt, aber es gibt noch einen weiteren Fall: Wenn kein Befehl ausgeführt werden muss , dh wenn der Befehl nur aus Zuweisungen (und möglicherweise Umleitungen) besteht. In diesem Fall bleibt die Zuordnung bestehen . VAR=VALUE OTHERVAR=OTHERVALUE
ist äquivalent zu VAR=VALUE; OTHERVAR=OTHERVALUE
. So nach IFS=. arr=($var)
, IFS
bleibt auf .
. Da Sie $IFS
in der Zuordnung zu arr
mit der Erwartung verwenden könnten, dass es bereits seinen neuen Wert hat, ist es sinnvoll, dass der neue Wert von IFS
für die Erweiterung von verwendet wird $var
.
Zusammenfassend können Sie nur IFS
für die temporäre Feldaufteilung verwenden:
- durch Starten einer neuen Shell oder einer Subshell (z. B.
third=$(IFS=.; set -f; set -- $var; echo "$3")
ist eine komplizierte Methode, mit der third=${var#*.*.}
Ausnahme, dass sie sich anders verhalten, wenn der Wert von var
weniger als zwei .
Zeichen enthält);
- in KSH, mit
IFS=. some-function
denen some-function
mit der KSH Syntax definiert ist function some-function …
;
- in bash und zsh,
IFS=. some-function
solange sie im einheitlichen Modus im Gegensatz zum Kompatibilitätsmodus ausgeführt werden.
IFS
bleibt auf.
" Eek. Nachdem ich den ersten Teil gelesen habe, macht das Sinn, aber bevor ich diesen Fragebogen gepostet habe, hätte ich das nicht erwartet.Die Antwort von @Gilles ist wirklich großartig, erklärt er (im Detail) ein komplexes Problem.
Ich glaube jedoch, dass die Antwort, warum dieser Befehl:
Funktioniert wie es funktioniert, ist die einfache Idee, dass die gesamte Befehlszeile analysiert wird, bevor sie ausgeführt wird. Und dass jedes "Wort" einmal von der Shell verarbeitet wird.
Die Zuweisungen sind wie
IFS=.
verzögert (Schritt 4 ist der letzte):Bis kurz bevor der Befehl ausgeführt wird und alle Erweiterungen in Argumenten zuerst verarbeitet werden, um diese ausführbare Zeile zu erstellen:
Der Wert von
$var
wird mit dem "alten" IFS bis erweitert,a.b.c
bevor dem Befehlprintf
die Argumente"%s\n"
und gegeben werdena.b.c
.Eval
Eine Verzögerungsstufe kann eingeführt werden durch
eval
:Die Zeile wird analysiert (1. Mal) und 'IFS =.' ist auf die Umgebung wie folgt eingestellt:
Dann wird es noch einmal analysiert:
Und dazu ausgeführt:
Der Wert von
$var
(abc) wird geteilt durch den Wert des IFS in Gebrauch:.
.Umgebung
Der komplexe und knifflige Teil ist das, was in der Umwelt gilt, wenn !!!
Das wird im ersten Teil der Antwort von Gilles sehr gut erklärt.
Mit einem zusätzlichen Detail.
Wenn dieser Befehl ausgeführt wird:
Der Wert von IFS bleibt in der gegenwärtigen Umgebung erhalten, ja:
IFS für eine einzelne Anweisung.
Es könnte jedoch vermieden werden: Setzen von IFS für eine einzelne Anweisung
quelle
Ihre Frage zu
ist ein Eckfall.
Dies liegt daran, dass der
macro expansion
Befehl in ausgeführt wird, bevor die Shell-VariableIFS=.
festgelegt wird.Mit anderen Worten: Wenn
$var
erweitert, wird der vorherigeIFS
Wert aktiv und dann aufIFS
gesetzt'.'
.quelle