
Warum tut
for i in {1..5}; do x="${i}" echo "$x"; done
nicht ausgegeben
1
2
3
4
5
?
Wie geht man dabei richtig vor?
(Geprüftfor i in {1..5}; do x=$(i) echo "$x"; done
-bash: i: Befehl nicht gefunden
und andere)
Antwort1
Beantwortung Ihrer Frage wie gestellt
Warum wird , , , ,
for i in {1..5}; do x="${i}" echo "$x"; done
nicht ausgegeben ?1
2
3
4
5
Der Grund liegt in der Reihenfolge, in der Operationen während der Ausführung ausgewertet werden. Sehen Sie sich diesen Befehl an
x="${i}" echo "$x"
Das bedeutet:
- Ersetzen Sie Variablen durch ihre Werte
- Weisen Sie der Variable einen temporären Wert zu
x
- Führen Sie den Befehl aus
Sie erhalten also
x=1 echo ""
(oderx=2 echo ""
usw.)- Für die Dauer dieses Befehls
x
wird auf den Wert gesetzt1
- Der Befehl wird ausgeführt:
echo ""
Wahrscheinlich haben Sie diesen Befehl als zwei Anweisungen gemeint: Weisen Sie einen Wert zu x
und geben Sie seinen Wert aus. Aber in der Shell-Syntax war das, was Sie geschrieben haben, vollkommen zulässiger Code, sodass die Shell ihn ohne Einwände ausführte.
Antwort2
Sie haben um Antworten auf zwei Fragen gebeten:
Sie haben um eine Erklärung gebeten, warum Ihr aktueller Code nicht die erwartete Ausgabe erzeugt.
Sie haben nach der richtigen Art und Weise gefragt, Ihren Code zu schreiben, damit er die erwartete Ausgabe erzeugt.
Wenn ich mir Ihren Code anschaue, kann ich zwei wahrscheinliche Erklärungen dafür erkennen, warum Sie den Code auf diese Art und Weise geschrieben haben:
Es besteht möglicherweise eine leichte Verwirrung über dieSyntax einer For-Schleife.
Es kann zu leichter Verwirrung hinsichtlich der Reihenfolge der Auswertung in einem so genannteneinfacher Befehl.
For-Schleifensyntax
Im ersten Fall würde ich sagen, dass Ihnen nach Ihrer Variablenzuweisung ein Semikolon fehlt. Wenn Sie Ihre For-Schleife in einer einzigen Zeile schreiben möchten, müssen Sie nach jedem Befehl im Schleifenkörper ein Semikolon einfügen. Versuchen Sie stattdessen Folgendes:
for i in {1..5}; do x="${i}"; echo "$x"; done
Eine andere Alternative wäre, die For-Schleife mit der mehrzeiligen Syntax zu schreiben, wobei anstelle der Semikolons Zeilenumbrüche verwendet werden:
for i in {1..5}
do
x="${i}"
echo "${x}"
done
Sie können Semikolons und Zeilenumbrüche auch mischen und anpassen, zum Beispiel:
for i in {1..5}; do
x="${i}"; echo "${x}"
done
Auswertung einfacher Befehle
Im zweiten Fall würde ich sagen, dass Sie wahrscheinlich angenommen haben, dass die Variablenzuweisung im Prolog des Befehls (also die x="$i"
Zuweisung) vor der Variablenerweiterung im Hauptteil des Befehls (also der Erweiterung von ${x}
in echo "${x}"
) erfolgt. Dies ist jedoch tatsächlich nicht der Fall. Um dies zu überprüfen, können wir auf die Seite übereinfache Befehlserweiterungim Bash-Handbuch oder imUnterabschnitt über einfache BefehleimPosix-SpezifikationBeide dieser Referenzen enthalten die folgende Passage:
Ein „einfacher Befehl“ ist eine Folge optionaler Variablenzuweisungen und Umleitungen in beliebiger Reihenfolge, optional gefolgt von Wörtern und Umleitungen, beendet durch einen Steueroperator.
Wenn ein bestimmter einfacher Befehl ausgeführt werden muss (das heißt, wenn eine bedingte Konstruktion wie eine UND-ODER-Liste oder eineFallAnweisung den einfachen Befehl nicht umgangen hat), werden die folgenden Erweiterungen, Zuweisungen und Umleitungen alle vom Anfang bis zum Ende des Befehlstextes ausgeführt:
Die Wörter, die als Variablenzuweisungen oder Umleitungen erkannt werden, gemäßShell-Grammatikregelnwerden zur Verarbeitung in den Schritten 3 und 4 gespeichert.
Die Wörter, die keine Variablenzuweisungen oder Umleitungen sind, müssen erweitert werden. Wenn nach ihrer Erweiterung noch Felder übrig bleiben, wird das erste Feld als Befehlsname betrachtet und die restlichen Felder sind die Argumente für den Befehl.
Umleitungen werden wie folgt durchgeführt:Umleitung.
Jede Variablenzuweisung muss vor der Zuweisung des Werts für die Tilde-Erweiterung, Parametererweiterung, Befehlsersetzung, arithmetische Erweiterung und Anführungszeichenentfernung erweitert werden.
Beachten Sie, dass die Variablenerweiterung im Befehl in Schritt 2 erfolgt, aber Schritt 1 sagt uns, dass die Variablenzuweisungen bis zu den Schritten 3 und 4 gespeichert werden. Daraus folgt, dass der Ausdruck echo "${x}"
erweitert wird, echo ""
bevor die Zuweisung x="${i}"
stattfindet. Dies erklärt, warum Sie eine leere Ausgabe erhalten haben.
Weitere Diskussionen zu diesem Thema finden Sie in den folgenden Beiträgen:
Antwort3
In zsh
wird eine dritte ${var::=value}
Form der Bourne-Operatoren verwendet ${var=value}
, ${var:=value}
bei denen die Zuweisung bedingungslos ist (im Gegensatz zu einer Zuweisung, die nur erfolgt, wenn die Variable nicht gesetzt/leer ist).
for i in {1..5}; do echo ${x::=$i}; done
Oder:
for i ({1..5}) echo ${x::=$i}
In bash
:
set -o posix # so the value of x remains after eval returns
for i in {1..5}; do x=$i eval 'echo "$x"'; done
Das heißt, Sie müssen $x
zum Zeitpunkt der Auswertung des Codes, der die Erweiterung enthält, eingestellt sein.
Für dezimale Ganzzahlwerte wie hier können Sie auch Folgendes tun:
for i in {1..5}; do echo "$((x = i))"; done
Oder Sie können immer den Bourne-Operator verwenden, nachdem Sie die Zeichenfolge auf leer ${var:=value}
gesetzt haben .x
for i in {1..5}; do x=; echo "${x:=$i}"; done