Ich habe gerade mehrere Antworten gefunden, zum Beispiel zum Parsen einer Textdatei mit Trennzeichen ... die das Konstrukt verwenden:
while IFS=, read xx yy zz;do
echo $xx $yy $zz
done < input_file
Wobei die IFS
Variable vor dem read
Befehl gesetzt wird.
Ich habe die Bash-Referenz gelesen , kann aber nicht herausfinden, warum dies legal ist.
Ich habe es versucht
$ x="once upon" y="a time" echo $x $y
von der Bash-Eingabeaufforderung wurde aber nichts wiedergegeben. Kann mir jemand sagen, wo diese Syntax in der Referenz definiert ist, mit der die IFS-Variable auf diese Weise festgelegt werden kann? Ist es ein Sonderfall oder kann ich etwas Ähnliches mit anderen Variablen tun?
bash
shell
environment-variables
Mike Lippert
quelle
quelle
Antworten:
Es steht unter Shell-Grammatik, Einfache Befehle (Hervorhebung hinzugefügt):
Sie können also eine beliebige Variable übergeben. Ihr
echo
Beispiel funktioniert nicht, da die Variablen an den Befehl übergeben und nicht in der Shell festgelegt werden. Die Shell wird erweitert$x
und$y
vor dem Aufrufen des Befehls. Das funktioniert zum Beispiel:quelle
man bash
auf meinem System ...Die definierten Variablen werden zu Umgebungsvariablen im gegabelten Prozess.
Wenn du läufst
Dann expandiert bash zuerst
$A
in""
und läuft dannHier ist der richtige Weg:
Beachten Sie die einfachen Anführungszeichen in
bash -c
, ansonsten haben Sie das gleiche Problem wie oben.Ihr Schleifenbeispiel ist also zulässig, da der in Bash integrierte Befehl 'read' in seinen Umgebungsvariablen nach IFS sucht und findet
,
. Deshalb,wird gedruckt
TEST is and I is test
Als letztes wird, wie bei der Syntax, in einer for-Schleife eine Zeichenkette erwartet. Deshalb musste ich Backticks verwenden, um daraus einen Befehl zu machen. While-Schleifen erwarten jedoch Befehlssyntax, z
IFS=, read xx yy zz
.quelle
A
Variablen wird bash$A
zu einer leeren Zeichenfolge erweitert , aber um Verwirrung zu vermeiden, würde ich nicht verwenden,""
da der Code nicht äquivalent zu istA="b" echo ""
. Es wird kein Argument dafür gebenecho
.man bash
Die Variablen werden vor der Variablenzuordnung erweitert. Aus dem offensichtlichen Grund
var=x
würde das auch anders funktionieren, abervar=$othervar
nicht. Dh Ihr$x
wird benötigt, bevor es verfügbar ist. Das ist aber nicht das Hauptproblem. Das Hauptproblem besteht darin, dass die Befehlszeile nur von der Shell-Umgebung geändert werden kann, die Zuweisung jedoch nicht Teil der Shell-Umgebung wird.Sie vermischen sich mit Funktionen: Sie möchten eine Befehlszeile ersetzen, aber die Variablendefinition in die Befehlsumgebung einfügen. Befehlszeilenersetzungen müssen von der Shell vorgenommen werden. Die Umgebung muss vom aufgerufenen Befehl explizit verwendet werden. Ob und wie dies geschieht, hängt vom Befehl ab.
Der Vorteil dieser Verwendung besteht darin, dass Sie die Umgebung für einen Unterprozess festlegen können, ohne die Shell-Umgebung zu beeinträchtigen.
Funktioniert wie erwartet, da in diesem Fall beide Funktionen kombiniert werden: Die Befehlszeilenersetzung wird nicht von der aufrufenden Shell, sondern von der Subprozess-Shell durchgeführt.
quelle
x="once upon" y="a time" eval 'echo $x $y'
wenn kein Unterprozess beteiligt ist, daeval
es sich um einen eingebauten Prozess handelt. Ich denke, das relevante Zitat aus der Manpage istThe environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments
. In Anbetracht des Beispiels der Frage muss es so sein, daread
es sich auch um ein eingebautes handelt und es mit einem zeitlich veränderten Zustand arbeitetIFS
.Der Befehl , den Sie bieten ist anders , weil
$x
und$y
expandiert werden , bevor derecho
Befehl ausgeführt wird , so dass ihre Werte in der aktuellen Shell verwendet werden, nicht die Werte , dieecho
in seiner Umgebung sehen würde , wenn es zu sehen waren.quelle
x
undy
gelten für die Umgebung,echo
in der sie ausgeführt werden, und nicht für die Umgebung, in der die zuecho
erweiterenden Argumente erweitert werden. DennIFS=, read xx yy zz
die gesamte Zeichenkette wird vomread
Befehl ungeteilt gelesen . Dann wird die Zeichenfolge aufgeteilt entsprechend dem Wert derIFS
mit den entsprechenden Teilen zugeordnet sindxx
,yy
undzz
.bash
zuerst die angegebene Befehlszeile analysiert wird, erkannt wird, dass zwei Variablenzuweisungen für die Umgebung des kommenden Befehls gelten, der auszuführende Befehl identifiziert wird (echo
), alle in den Argumenten gefundenen Parameter erweitert werden und dann der Befehl ausgeführt wirdecho
mit den erweiterten Argumenten.echo
ich nicht sicher, ob es die Variable "sehen" konnte, da es ein eingebauter Befehl ist und daher nicht in einer Subshell ausgeführt wird, die eine eigene Umgebung haben könnte. Aber ich habe es ausprobiert,eval
womit auch ein eingebaut ist und es ja weiß. ZB versuchen Sie,a=xyz eval 'echo $BASHPID $a; grep -z ^a /proc/$BASHPID/{,task/*}/environ'; echo $BASHPID $a
was zeigt, dassa
nur innerhalb festgelegt wirdeval
, obwohl die PID gleich ist und die Umgebung während der Auswertung nicht verändert wird! (Um darauf zuzugreifen/proc
, müssen Sie dies unter Linux ausführen.) Es scheint, dass Bash hier zusätzliche Magie ausübt.Ich gehe auf das Gesamtbild von " Warum ist es legal?"
Antwort: Damit Sie ein Programm aufrufen oder aufrufen können und für diesen Aufruf nur eine Variable mit einer bestimmten Variablen verwenden können.
Beispiel: Sie haben einen Parameter für eine Datenbankverbindung mit dem Namen 'db_connection' und übergeben normalerweise 'test' als Namen für Ihre Testdatenbankverbindung. In der Tat können Sie es sogar als Standard festlegen, den Sie dann nicht explizit übergeben müssen. Manchmal möchten Sie jedoch mit der ci-Datenbank arbeiten. Sie übergeben den Parameter also als 'ci' und das aufgerufene Programm verwendet diesen Datenbankparameter als Namen der Datenbank, die für alle Datenbankaufrufe verwendet werden soll. Wenn Sie den Vorgang für den nächsten Lauf nicht wiederholen und nur das Programm aufrufen, wird die Variable auf den vorherigen Standardwert zurückgesetzt.
quelle
Sie können auch verwenden
;
. Es wird vorher ausgewertet, weil es ein Befehlstrennzeichen ist.quelle