it-swarm.com.de

Warum ist das Setzen einer Variablen vor einem Befehl in bash zulässig?

Ich habe gerade einige Antworten gefunden, wie zum Beispiel Parsen einer begrenzten Textdatei ... , die das Konstrukt verwenden:

while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

dabei wird die Variable IFS vor dem Befehl read gesetzt.

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

vom Bash-Befehl Eingabeaufforderung aber nichts wiedergegeben. Kann mich jemand darauf hinweisen, 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 machen?

76
Mike Lippert

Es befindet sich unter Shell-Grammatik, Einfache Befehle (Hervorhebung hinzugefügt):

Ein einfacher Befehl ist ein Folge von optionalen Variablenzuweisungen gefolgt von einem durch Leerzeichen getrennten Wörter und Umleitungen und wird von einem Steueroperator beendet. Das erstes Wort gibt den auszuführenden Befehl an und wird als Argument Null übergeben. Die restlichen Wörter werden als Argumente an den aufgerufenen Befehl übergeben.

Sie können also jede gewünschte Variable übergeben. Ihr echo -Beispiel funktioniert nicht, da die Variablen an den Befehl übergeben und nicht in der Shell festgelegt werden. Die Shell erweitert $x und $y vor Aufrufen des Befehls. Dies funktioniert zum Beispiel:

$ x="once upon" y="a time" bash -c 'echo $x $y'
once upon a time
80
derobert

Die definierten Variablen werden wie Umgebungsvariablen im gegabelten Prozess.

Wenn du läufst

A="b" echo $A

dann erweitert bash zuerst $A in "" und läuft dann aus

A="b" echo

Hier ist der richtige Weg:

x="once upon" y="a time" bash -c 'echo $x $y'

Beachten Sie die einfachen Anführungszeichen in bash -c, Andernfalls haben Sie das gleiche Problem wie oben.

Ihr Schleifenbeispiel ist also legal, da der in bash eingebaute Befehl 'read' in seinen Umgebungsvariablen nach IFS sucht und , Findet. Deshalb,

for i in `TEST=test bash -c 'echo $TEST'`
do
  echo "TEST is $TEST and I is $i"
done

druckt TEST is and I is test

Schließlich wird für die Syntax in einer for-Schleife eine Zeichenfolge erwartet. Deshalb musste ich Backticks verwenden, um daraus einen Befehl zu machen. While-Schleifen erwarten jedoch Befehlssyntax wie IFS=, read xx yy zz.

30
Mike Fairhurst

man bash

UMGEBUNG

[...] Die Umgebung für einfache Befehle oder Funktionen kann vorübergehend erweitert werden, indem Parameterzuweisungen vorangestellt werden, wie oben in PARAMETER beschrieben. Diese Zuweisungsanweisungen wirken sich nur auf die Umgebung aus, die von diesem Befehl angezeigt wird.

Die Variablen werden erweitert, bevor die Variablenzuweisung erfolgt. Aus dem offensichtlichen Grund, dass var=x würde auch anders funktionieren, aber var=$othervar würde nicht. Das heißt, Ihre $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 verwechseln mit Funktionen: Sie möchten eine Befehlszeilenersetzung, fügen jedoch die Variablendefinition in die Befehlsumgebung ein. Das Ersetzen der Befehlszeile muss durch die Shell erfolgen. 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.

x="once upon" y="a time" bash -c 'echo $x $y'

funktioniert wie erwartet, da in diesem Fall beide Funktionen kombiniert werden: Das Ersetzen der Befehlszeile erfolgt nicht durch die aufrufende Shell, sondern durch die Subprozess-Shell.

8
Hauke Laging

Der von Ihnen angegebene Befehl ist unterschiedlich, da $x und $y werden erweitert vor der Befehl echo wird ausgeführt, daher werden ihre Werte in der Shell current verwendet, nicht die Werte, die echo verwenden würde in seiner Umgebung sehen, ob es aussehen würde.

4
chepner

Ich gehe für das Gesamtbild von "warum es ist legal"

Antwort: Damit Sie ein Programm aufrufen oder aufrufen können und für diesen Aufruf nur eine Variable mit einer bestimmten Variablen verwenden.

Beispiel: Sie haben einen Parameter für eine Datenbankverbindung mit dem Namen 'db_connection' und übergeben normalerweise 'test' als Namen für Ihre Testdatenbankverbindung. Sie können 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 beim nächsten Lauf den Ansatz nicht wiederholen und nur das Programm aufrufen, kehrt die Variable zu ihrem vorherigen Standardwert zurück.

2
Michael Durrant

Sie können auch ; Verwenden. Es wird vorher ausgewertet, da es ein Befehlstrennzeichen ist.

x="once upon" y="a time"; echo $x $y
0
camabeh