Mir ist aufgefallen, dass {
bei der Klammererweiterung verwendet werden kann:
echo {1..8}
oder in Befehlsgruppierung:
{ls;echo hi}
Woher kennt bash den Unterschied?
bash
shell-script
Liebesfeder
quelle
quelle
{
als würde es als Befehlsliste interpretiert, wenn es zu Beginn eines Befehls erscheint, und als geschweifte Erweiterung, aber ich bin mir nicht sicher.{ls;echo hi}
ist nicht legalbash
. Sie benötigen nach der öffnenden Klammer ein Leerzeichen und vor der schließenden ein Semikolon.Antworten:
Ein vereinfachtes Grund ist die Existenz eines Zeichens: space.
Klammererweiterungen verarbeiten keine (nicht in Anführungszeichen gesetzten) Leerzeichen.
Eine
{...}
Liste benötigt (nicht in Anführungszeichen gesetzte) Leerzeichen.Die detailliertere Antwort lautet, wie die Shell eine Befehlszeile analysiert .
Der erste Schritt zum Parsen (Verstehen) einer Befehlszeile besteht darin, sie in Teile zu unterteilen.
Diese Teile (normalerweise als Wörter oder Token bezeichnet) ergeben sich aus der Unterteilung einer Befehlszeile an jedem Metazeichen aus dem Link :
Metazeichen: spacetabenter;,<>|und &.
Nach dem Teilen können Wörter von einem Typ sein (wie von der Shell verstanden):
LC=ALL ...
LC=ALL echo
LC=ALL echo "hello"
LC=ALL echo "hello" >&2
Klammererweiterung
Nur wenn eine "geschweifte Klammer" (ohne Leerzeichen oder Metazeichen) ein einzelnes Wort ist (wie oben beschrieben) und nicht in Anführungszeichen steht , ist sie ein Kandidat für die "geschweifte Klammer". Weitere Überprüfungen der internen Struktur werden später durchgeführt.
Also:
{ls,-l}
Qualifiziert sich als "Klammererweiterung", umls -l
entweder alsfirst word
oderargument
(in bash ist zsh anders) zu werden.Aber das wird nicht:
{ls ,-l}
. Bash teilt spacedie Zeile in zwei Wörter auf und parst sie:{ls
und,-l}
das löst ein auscommand not found
(das Argument,-l}
geht verloren):Ihre Zeile:
{ls;echo hi}
wird aufgrund der beiden Metazeichen ;und nicht zu einer "Klammererweiterung" space.Es wird in diese drei Teile unterteilt werden:
{ls
neuen Befehl:echo
hi}
. Verstehen Sie, dass dies den ;Start eines neuen Befehls auslöst. Der Befehl{ls
wird nicht gefunden und der nächste Befehl wird ausgegebenhi}
:Wenn es nach einem anderen Befehl platziert wird, startet es trotzdem einen neuen Befehl nach dem ;:
Liste
Einer der „Verbindung Befehle“ ist eine „Brace List“ (meine Worte):
{ list; }
.Wie Sie sehen, wird es mit Leerzeichen und einem Abschluss definiert
;
.Die Leerzeichen und ;werden benötigt, da beide
{
und}
"Reserved Words " sind.Um als Wörter erkannt zu werden, müssen sie daher von Metazeichen umgeben sein (fast immer:) space.
Wie in Punkt 2 der verlinkten Seite beschrieben
Ihr Beispiel:
{ls;echo hi}
ist keine Liste.Es braucht einen Schluss ;und ein Leerzeichen (mindestens) danach {. Der letzte }wird durch den Abschluss definiert ;.
Dies ist eine Liste
{ ls;echo hi; }
. Und das{ ls;echo hi;}
ist auch (seltener verwendet, aber gültig) (Danke @choroba für die Hilfe).Als Argument (die Shell kennt den Unterschied) für einen Befehl löst sie jedoch einen Fehler aus:
Aber seien Sie vorsichtig, wenn Sie glauben, dass die Shell analysiert:
quelle
;
und}
.{ ls;}
funktioniert, da das Semikolon bereits ein Metazeichen ist.Der Block
{
ist ein Shell-Schlüsselwort, daher muss er durch ein Leerzeichen vom nächsten Wort getrennt werden, während bei der Klammererweiterung kein Leerzeichen vorhanden sein darf (wenn Sie ein Leerzeichen in Klammern setzen müssen, müssen Sie es maskieren:)echo {\ ,a}{b,c}
.Sie können die geschweifte Klammer zu Beginn eines Befehls verwenden:
Sie können es jedoch nicht zum Erweitern eines Blocks verwenden, da das Parsen der Gruppierungsbefehle vor den Erweiterungen erfolgt:
quelle
Es weiß durch Überprüfen der Syntax der Befehlszeile. Ebenso ist bekannt, dass im Ausdruck
echo echo
das erste Echo als Befehl und das zweite Echo als Parameter des ersten Echos behandelt werden soll.In bash ist es sehr einfach, da
{ cmd; }
Leerzeichen und Semikolon enthalten sein sollten. Zum Beispiel in zsh werden sie jedoch nicht benötigt, aber durch die Analyse des{}
Shell- Kontexts kann festgestellt werden, was mit dem Inhalt geschehen soll.Folgendes berücksichtigen:
Beide geben das aktuelle Datum zurück, aber
Gibt zurück,
1 2 3
weil die Shell{}
ein Argument für den Befehl kenntecho
und es daher erweitert werden sollte.quelle
{
gefolgt von nicht angegebenem Leerzeichen wird die Erweiterung der Klammern in Bash nicht gestartet.{
. Leerzeichen ohne Anführungszeichen können nirgendwo stehen, da die Shell die gesamte Befehlszeile in Leerzeichen aufteilt.Erstens muss die zusammengesetzte Klammer ein Wort für sich und das erste Wort der Befehlszeile sein:
Zweitens sind einzelne Zahnspangen nichts Besonderes (wie Sie oben sehen können). Leere Klammern sind auch nichts Besonderes:
Alles ohne Komma ist auch nur sich selbst
Hier beginnt die Aktion.
Um die Klammererweiterung zu aktivieren, benötigen wir ein einzelnes Wort (nicht in Felder auf Leerzeichen getrennt), in dem mindestens eine Instanz
{...}
vorkommt, in der mindestens ein Komma vorkommt.Dies kann übrigens das erste Wort in der Befehlszeile sein:
quelle