Warum benötigt eine Klammerbefehlsgruppe nach dem Öffnen der Klammer in der POSIX-Shell-Grammatik Leerzeichen?


10

TL; DR : Warum benötigt die POSIX- {Klammergruppe Leerzeichen nach dem reservierten Wort, die Unterschale jedoch nicht nach dem reservierten Wort (?

Die POSIX-Shell-Grammatik definiert Klammergruppe und Subshell wie folgt

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Wenn wir das wörtlich lesen, sind Leerzeichen von Bedeutung. Dies würde bedeuten, dass es einen Raum geben muss, der die öffnende und schließende Klammer und Klammer wie in beschreibt

{ echo hello world; }

( echo hello world )

Dies würde auch mit den Definitionen des zusammengesetzten Befehls übereinstimmen :

Jeder dieser zusammengesetzten Befehle hat am Anfang ein reserviertes Wort oder einen Steueroperator und am Ende ein entsprechendes reserviertes Terminatorwort oder einen Operator.

Was jedoch keinen Sinn ergibt, ist, warum (list)und ( list )funktioniert einwandfrei (dieser Platz danach (ist nicht erforderlich), jedoch muss die Klammererweiterung einen führenden Platz haben, dh {echo hello;}würde nicht funktionieren.

Natürlich wäre es sinnvoll, ein reserviertes Wort, das als Shell-Wort behandelt wird, danach ein Leerzeichen zu benötigen, um mit dem Konzept der Feldaufteilung übereinzustimmen . Die Definition selbst erwähnt jedoch keine Leerzeichen. Wenn darüber hinaus {und (sind beide als reservierte Wörter von POSIX Definition der Verbindung Befehl, warum sie anders in Bezug auf die Raumzeichen nach diesen reservierten Wörter behandelt werden? Im Handbuch zu ksh (1) heißt es nun:

Wörter, bei denen es sich um Zeichenfolgen handelt, werden durch nicht zitierte Leerzeichen (Leerzeichen, Tabulator und Zeilenumbruch) oder Metazeichen (<,>, |,;, &, (und)) begrenzt.

Mit anderen Worten ist es sinnvoll, dass ksh (als Wortbegrenzer erkennt , wobei das erste Wort ein Befehl oder eine Variablenzuweisung ist. POSIX scheint jedoch nicht (als Meta-Zeichen zu erwähnen . Die einzig mögliche Erklärung, die ich für die POSIX-Grammatik gefunden habe, ist, dass sie {als "Token" betrachtet wird, wobei as (nicht als eines aufgeführt ist.

/* These are reserved words, not operator tokens, and are
   recognized when reserved words are recognized. */


%token  Lbrace    Rbrace    Bang
/*      '{'       '}'       '!'   */

Was wäre also eine genaue Begründung für diese Diskrepanz?

Akzeptierte Antwort Hinweise:

  • Das akzeptierte Häkchen wurde in Isaacs Antwort verschoben, da es den Standard selbst enthält, der meine Frage direkt anspricht:

    Zum Beispiel sind '(' und ')' Steuerungsoperatoren, so dass <space>in (Liste) keine benötigt wird. '{' Und '}' sind jedoch reservierte Wörter in {list;}, so dass in diesem Fall die führenden <space>und <semicolon>erforderlich sind.

  • Kusalanandas Antwort annehmen . Kusalanandas Antwort spricht das an, was ich brauchte, allerdings hauptsächlich aus informeller und intuitiver Sicht. es weist darauf hin, {ist ein reserviertes Wort und (ist Operator. Michael Homer bemerkte dasselbe auch in den Kommentaren - in der Definition des zusammengesetzten Befehls heißt es (Hervorhebung hinzugefügt):

    Jeder dieser zusammengesetzten Befehle hat am Anfang ein reserviertes Wort oder einen Steueroperator

  • {sind als reserviertes Wort definiert, ähnlich foroder whilein der Shell-Grammatik aufgeführt (siehe den letzten Codeblock in der Frage).

  • Abschnitt 2.9 besagt (Hervorhebung hinzugefügt):

    Insbesondere enthalten die Darstellungen einen Abstand zwischen Token an einigen Stellen, an denen <blank>s nicht erforderlich wäre (wenn einer der Token ein Operator ist).

  • Während der Standard nicht explizit (als Operator definiert (wird, wird er als Operator bezeichnet. Insbesondere Abschnitt 2.9.2 sagt

    Wenn die Pipeline mit dem reservierten Wort beginnt! und Befehl1 ist ein Unterschalenbefehl. Die Anwendung muss sicherstellen, dass der Operator (am Anfang von Befehl1 durch ein oder mehrere Zeichen vom! getrennt ist. Das Verhalten des reservierten Wortes! unmittelbar gefolgt vom Operator (ist nicht angegeben.

  • Die Frage zum Stapelüberlauf durch digitales Trauma weist auf Abschnitt 2.4 zu reservierten Wörtern hin:

    Diese Erkennung erfolgt nur, wenn keines der Zeichen in Anführungszeichen steht und wenn das Wort wie folgt verwendet wird:

    -Das erste Wort eines Befehls

  • Wie in Kusalanandas Antwort erwähnt: "Die in der POSIX-Grammatik angezeigten Leerzeichen sind keine Leerzeichen, die in den Shell-Eingabedaten vorhanden sein müssen, sondern nur eine Möglichkeit, die Grammatik selbst anzuzeigen. Die Tatsache, dass die geschweiften Klammern reservierte Wörter sind, impliziert dies Sie müssen von Leerzeichen umgeben sein. "Wie von Michael Homer in den Kommentaren erwähnt:" Wenn die Leerzeichen für sich genommen bedeutsam wären, müssten sie in der Produktion aufgeführt werden. "

Fall abgeschlossen.


3
Wenn die Räume für sich genommen bedeutsam wären, müssten sie in der Produktion aufgeführt werden.
Michael Homer

2
"Wenn {und (werden beide nach der POSIX-Definition des zusammengesetzten Befehls als reservierte Wörter betrachtet", vgl. "Jeder dieser zusammengesetzten Befehle hat am Anfang ein reserviertes Wort oder einen Steueroperator ".
Michael Homer

2
@SergiyKolodyazhnyy Ich glaube, er meint, wenn der Raum signifikant gewesen wäre, hätte die Grammatik ein explizites Leerzeichen ( ' ') enthalten müssen. Stattdessen werden die Leerzeichen durch die Wörter impliziert, die Wörter sind.
Kusalananda

2
Die Spezifikationsdefinition der Token-Klasse ist ... gelinde gesagt umständlich. Die ganze Grammatik ist ziemlich schrecklich und die Spezifikation mischt definierende Dinge in Prosa im Text (manchmal implizit!), In den Prosaregeln vor der Grammatik und in der Grammatik selbst. Es ist ziemlich unverständlich, wenn Sie die Antwort noch nicht kennen und rückwärts arbeiten. Die lexikalischen Regeln werden alle rückwärts definiert, indem ein neues Token beginnt, anstatt zu beschreiben, was das Token enthält. Es ist nur ein Durcheinander.
Michael Homer

1
@Sergiy In der formalen Grammatik beschreibt eine Produktion (oder Produktionsregel), wie Sie etwas aus etwas anderem generieren können. Siehe en.wikipedia.org/wiki/Production_%28computer_science%29 So command : simple_command | compound_command | compound_command redirect_list | function_definition ;ist eine Produktion , die sagt , wo Sie einen Befehl haben, kann es mit Umleitung oder eine Funktionsdefinition ein einfacher Befehl, Verbindung einen Befehl oder eine Verbindung Befehl sein.
Muru

Antworten:


6

Dies ist eine Einschränkung der Art und Weise, wie die Shell Linien in Token zerlegt.

Die Shell liest Zeilen aus der Eingabedatei und konvertiert sie gemäß Abschnitt 2 "Shell-Einführung" entweder in ein Wort oder einen Operator :

  1. Die Shell unterteilt die Eingabe in Token: Wörter und Operatoren

{ist ein reserviertes Wort

Einige Wörter sind reservierte Wörter

Reservierte Wörter sind Wörter, die für die Shell eine besondere Bedeutung haben. Die folgenden Wörter werden als reservierte Wörter anerkannt:

! { } case do done elif else esac fi for if in then until while

Wörter, die als Wörter erkannt werden sollen, müssen abgegrenzt werden .

Reservierte Wörter werden nur erkannt, wenn sie abgegrenzt sind ...

Meistens durch Leerzeichen (Punkt 7) und durch Operatoren.

  1. Wenn das aktuelle Zeichen ein nicht in Anführungszeichen gesetztes <Leerzeichen> ist, wird jedes Token, das das vorherige Zeichen enthält, begrenzt und das aktuelle Zeichen wird verworfen.

(ist ein Operator

Die Betreiber stehen für sich :

während die Betreiber selbst Begrenzer sind.

Wo "Operatoren" sind entweder :

3.260 Bediener

In der Shell-Befehlssprache entweder ein Steuerungsoperator oder ein Umleitungsoperator .

Umleitungsoperatoren sind :

Umleitungsoperator

In der Shell-Befehlssprache ein Token, das eine Umleitungsfunktion ausführt. Es ist eines der folgenden Symbole:

<     >     >|     <<     >>     <&     >&     <<-     <>

Steuerungsoperatoren sind :

3.113 Bediener steuern

In der Shell-Befehlssprache ein Token, das eine Steuerfunktion ausführt. Es ist eines der folgenden Symbole:

&   &&   (   )   ;   ;;   newline   |   ||

Fazit

'(' Und ')' sind also Steueroperatoren, während '{' '}' reservierte Wörter sind.

Und genau die gleiche Beschreibung Ihrer Frage finden Sie in der Spezifikation :

Zum Beispiel sind '(' und ')' Steueroperatoren, so dass in (Liste) kein <Leerzeichen> benötigt wird. '{' Und '}' sind jedoch reservierte Wörter in {list;}, sodass in diesem Fall das führende <Leerzeichen> und das <Semicolon> erforderlich sind.

Was genau erklärt, warum nach a ein Leerzeichen (oder ein anderes Trennzeichen) erforderlich ist {.

Dies ist gültig:

{ echo yes;}

Wie ist das:

{(echo yes);}

Dies:

{(echo yes)}

Oder sogar das:

{>/dev/tty echo yes;}

Nun, das letzte Zitat ist genau richtig! + 1'ed. Ich muss die Frage und die Antworten jetzt überprüfen
Sergiy Kolodyazhnyy

13

Der Unterschied zwischen den geschweiften Klammern und Klammern sind , dass die Klammern (und !) sind reservierte Worte, wie for, if, thenusw. , während Klammern Bekämpfer sind. Wörter müssen durch Leerzeichen getrennt werden.

Dies bedeutet, dass genau wie Sie nicht haben können

foriin*; do

du kannst nicht haben

{somecommand;} >file

oder

if !somecommand; then

Die in der POSIX-Grammatik angezeigten Leerzeichen sind keine Leerzeichen, die in den Shell-Eingabedaten vorhanden sein müssen, sondern nur eine Möglichkeit, die Grammatik selbst anzuzeigen. Es ist die Tatsache, dass die Klammern reservierte Wörter sind , die impliziert, dass sie von Leerzeichen umgeben sein müssen, während die Klammern einer Unterschale dies nicht tun.


1
Nun, dies scheint ziemlich genau darauf zu antworten, und ich sehe, dass darin steht: "Insbesondere enthalten die Darstellungen Abstände zwischen Token an einigen Stellen, an denen <leerzeichen> nicht erforderlich wären (wenn einer der Token ein Operator ist)." Nur eine Frage: Wo definiert der Standard (als Operator? Es ist zumindest nicht in der Grammatik
Sergiy Kolodyazhnyy

@ MichaelHomer Ah, "Steuerungsoperator", genau wie ;. Dank dafür.
Kusalananda

Die Steuerungsoperatoren sind oben in der Manpage unter DEFINITIONEN aufgeführt. Wir könnten ()als Steuerungsoperatoren betrachten, |bei denen es sich bei beiden um Unterschalen handelt. Und { }funktioniert in der aktuellen Shell und kann keine Subshell beinhalten.
Glenn Jackman

@Kusalananda Gefunden, Abschnitt 2.9.2: "Wenn die Pipeline mit dem reservierten Wort beginnt! Und command1 ein Subshell-Befehl ist, muss die Anwendung sicherstellen, dass der Operator (am Anfang von command1 durch ein oder mehrere <vom! Getrennt ist." leere> Zeichen. Das Verhalten des reservierten Wortes! unmittelbar gefolgt vom Operator (ist nicht spezifiziert. "Keine klare Definition, aber der Standard nennt es (Operator
Sergiy Kolodyazhnyy

@glennjackman Zwar handelt es sich bei Pipelines um Subshells, dies ist jedoch nicht die Art der Definition, die angemessen erscheint. Der Standard erwähnt auch, dass es in einigen Implementierungen in Ordnung ist, dass die Pipeline in der aktuellen Shell-Ausführungsumgebung ausgeführt wird (und ich weiß, dass sie im Standard enthalten ist, da ich den Text gestern gesehen habe und jetzt danach suche). Ihr Vorschlag hat mich jedoch darauf hingewiesen, das Zitat zu finden, das ich oben kommentiert habe, wo zumindest der Standard es Operator nennt , obwohl es nicht explizit als eins definiert wird
Sergiy Kolodyazhnyy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.