Pourquoi un groupe de commandes d'accolades a-t-il besoin d'espaces après l'accolade d'ouverture dans POSIX Shell Grammar?

10

TL; DR : Pourquoi le groupe d'accolades POSIX a-t-il besoin d'espaces après le {mot réservé mais pas le sous-shell après le mot réservé (?

La grammaire du shell POSIX définit le groupe d'accolades et le sous-shell comme suit

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Maintenant, si nous lisons cela littéralement, les espaces sont importants. Cela signifierait qu'il doit y avoir un espace délimitant l'accolade d'ouverture et de fermeture et la parenthèse comme dans

{ echo hello world; }

( echo hello world )

Cela s'alignerait également avec les définitions des commandes composées :

Chacune de ces commandes composées a un mot réservé ou un opérateur de commande au début, et un mot ou opérateur réservé de terminaison correspondant à la fin.

Cependant, ce qui n'a pas de sens, c'est pourquoi (list)et ( list )fonctionne très bien (cet espace (n'est pas nécessaire après), mais l'expansion de l'accolade doit avoir un espace de tête, c'est {echo hello;}-à- dire ne fonctionnerait pas.

Bien sûr, un mot réservé traité comme un mot shell aurait du sens d'avoir besoin d'un espace par la suite pour s'aligner sur le concept de division de champ , mais la définition elle-même ne fait aucune mention d'espaces. De plus, si {et (sont tous deux considérés comme des mots réservés par la définition POSIX de la commande composée, pourquoi sont-ils traités différemment en ce qui concerne le caractère espace après ces mots réservés? Maintenant, le manuel de ksh (1) indique:

Les mots, qui sont des séquences de caractères, sont délimités par des espaces blancs sans guillemets (espace, tabulation et nouvelle ligne) ou des méta-caractères (<,>, |,;, &, (et))

En d'autres termes, il est logique que ksh reconnaîtrait (comme délimiteur de mot, où le premier mot serait une commande ou une affectation de variable. POSIX, cependant, ne semble pas mentionner (comme méta-caractère. La seule explication possible que j'ai trouvée en ce qui concerne la grammaire POSIX est qu'elle {est considérée comme un "jeton", où as (n'est pas répertorié comme un.

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


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

Alors, quel serait le raisonnement précis de cet écart?

Notes de réponse acceptées:

  • Déplacement de la coche acceptée dans la réponse d' Isaac car elle fournit une forme standard de la norme elle - même qui répond directement à ma question:

    Par exemple, '(' et ')' sont des opérateurs de contrôle, de sorte qu'aucun <space>n'est nécessaire dans (liste). Cependant, '{' et '}' sont des mots réservés dans {list;}, de sorte que dans ce cas, le début <space>et <semicolon>sont requis.

  • Accepter la réponse de Kusalananda . La réponse de Kusalananda répond à ce dont j'avais besoin, mais surtout d'un point de vue informel et intuitif; il indique qu'il {s'agit d'un mot réservé et qu'il (est opérateur. Michael Homer a également noté la même chose dans les commentaires - selon la définition de la commande composée (italiques ajoutés):

    Chacune de ces commandes composées a un mot réservé ou un opérateur de contrôle au début

  • {sont définis comme des mots réservés, similaires à forou while, répertoriés dans la grammaire du shell (voir le dernier bloc de code de la question)

  • La section 2.9 précise (je souligne):

    En particulier, les représentations incluent l'espacement entre les jetons à certains endroits où <blank>s ne serait pas nécessaire (lorsque l'un des jetons est un opérateur).

  • Bien que la norme ne définisse pas explicitement (comme un opérateur, (est appelée opérateur; en particulier, la section 2.9.2 dit

    Si le pipeline commence par le mot réservé! et command1 est une commande de sous-shell, l'application doit s'assurer que l'opérateur (au début de la commande1 est séparé du! par un ou plusieurs caractères. Le comportement du mot réservé! immédiatement suivi par l'opérateur (n'est pas spécifié).

  • La question sur le débordement de pile par Digital Trauma souligne la section 2.4 sur les mots réservés:

    Cette reconnaissance ne se produit que si aucun des caractères n'est cité et lorsque le mot est utilisé comme:

    -Le premier mot d'une commande

  • Comme mentionné dans la réponse de Kusalananda "Les espaces affichés dans la grammaire POSIX ne sont pas des espaces qui doivent être là dans les données d'entrée du shell, mais juste un moyen d'afficher la grammaire elle-même. C'est le fait que les accolades sont des mots réservés qui implique que ils doivent être entourés d'espaces blancs "Comme mentionné par Michael Homer dans les commentaires:" Si les espaces étaient importants en soi, ils devraient être répertoriés dans la production "

Affaire classée.

Sergiy Kolodyazhnyy
la source
3
Si les espaces étaient importants en soi, ils devraient être répertoriés dans la production.
Michael Homer
2
"De plus, si {et (sont tous deux considérés comme des mots réservés par la définition POSIX de la commande composée" cf. "Chacune de ces commandes composées a un mot réservé ou un opérateur de contrôle au début".
Michael Homer
2
@SergiyKolodyazhnyy Je pense qu'il veut dire que si l'espace était significatif, la grammaire aurait dû inclure un caractère d'espace explicite ( ' '). Au lieu de cela, les espaces sont impliqués par ce que les jetons sont des mots.
Kusalananda
2
La définition des spécifications de la classe de jetons est ... maladroite, c'est le moins qu'on puisse dire. Toute la grammaire est assez terrible et la spécification mélange la définition des choses dans la prose dans le texte (parfois implicitement!), Dans les règles de prose précédant la grammaire et dans la grammaire elle-même. C'est assez incompréhensible si vous ne connaissez pas déjà la réponse et travaillez à l'envers. Les règles lexicales sont toutes définies à l'envers, par ce qui commence un nouveau jeton, plutôt que de décrire ce que le jeton contient. C'est juste un gâchis tout autour.
Michael Homer
1
@Sergiy dans la grammaire formelle, une production (ou règle de production) décrit comment vous pouvez générer quelque chose d'autre. Voir en.wikipedia.org/wiki/Production_%28computer_science%29 Il en command : simple_command | compound_command | compound_command redirect_list | function_definition ;va de même pour une production qui indique où vous pouvez avoir une commande, il peut s'agir d'une commande simple, d'une commande composée ou d'une commande composée avec redirection ou d'une définition de fonction.
muru

Réponses:

6

C'est une limitation de la façon dont le shell rompt les lignes en jetons.

Le shell lit les lignes du fichier d'entrée et selon la section 2 "Introduction au shell", il les convertit soit en un mot, soit en un opérateur :

  1. Le shell divise l'entrée en jetons: mots et opérateurs

{est un mot réservé

Certains mots sont des mots réservés

Les mots réservés sont des mots qui ont une signification particulière pour le shell. Les mots suivants sont reconnus comme mots réservés:

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

Les mots, pour être reconnus comme des mots, doivent être délimités .

Les mots réservés ne sont reconnus que lorsqu'ils sont délimités ...

Surtout par des blancs (point 7) et par des opérateurs.

  1. Si le caractère courant est un <blanc> non guillemé, tout jeton contenant le caractère précédent est délimité et le caractère courant doit être jeté.

(est un opérateur

Les opérateurs sont autonomes :

tandis que les opérateurs sont eux-mêmes des délimiteurs.

Où les "opérateurs" sont soit :

3.260 Opérateur

Dans le langage de commande shell, soit un opérateur de contrôle , soit un opérateur de redirection .

Les opérateurs de redirection sont :

Opérateur de redirection

Dans le langage de commande shell, un jeton qui exécute une fonction de redirection. Il s'agit de l'un des symboles suivants:

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

Les opérateurs de contrôle sont :

3.113 Opérateur de contrôle

Dans le langage de commande shell, un jeton qui exécute une fonction de contrôle. Il s'agit de l'un des symboles suivants:

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

Conclusion

Ainsi, '(' et ')' sont des opérateurs de contrôle tandis que '{' '}' sont des mots réservés.

Et la même description exacte de votre question se trouve dans la spécification :

Par exemple, '(' et ')' sont des opérateurs de contrôle, de sorte qu'aucun <espace> n'est nécessaire dans (liste). Cependant, '{' et '}' sont des mots réservés dans {list;}, de sorte que dans ce cas, les espaces <space> et <semicolon> sont requis.

Ce qui explique exactement pourquoi un espace (ou un autre délimiteur) est nécessaire après a {.

Ceci est valable:

{ echo yes;}

Comme ceci:

{(echo yes);}

Cette:

{(echo yes)}

Ou même ceci:

{>/dev/tty echo yes;}
Isaac
la source
Eh bien, la dernière citation est exacte! + 1'ed. Je vais devoir revoir la question et les réponses maintenant
Sergiy Kolodyazhnyy
13

La différence entre les accolades et les parenthèses sont que les accolades (et !) sont des mots réservés, tout comme for, if, thenetc. , tandis que les parenthèses sont les opérateurs de contrôle. Les mots doivent être séparés par des espaces.

Cela signifie que tout comme vous ne pouvez pas avoir

foriin*; do

tu ne peux pas avoir

{somecommand;} >file

ou

if !somecommand; then

Les espaces affichés dans la grammaire POSIX ne sont pas des espaces qui doivent être présents dans les données d'entrée du shell, mais simplement un moyen d'afficher la grammaire elle-même. C'est le fait que les accolades sont des mots réservés qui implique qu'ils doivent être entourés d'espaces, contrairement aux parenthèses d'un sous-shell.

Kusalananda
la source
1
Eh bien, cela semble à peu près y répondre et je vois que cela dit "En particulier, les représentations incluent l'espacement entre les jetons à certains endroits où des <blanc> ne seraient pas nécessaires (lorsque l'un des jetons est un opérateur)". Juste une question: où la norme définit-elle (comme opérateur? Ce n'est pas dans la section de grammaire au moins
Sergiy Kolodyazhnyy
@MichaelHomer Ah, "opérateur de contrôle", tout comme ;. Merci pour ça.
Kusalananda
Les opérateurs de contrôle sont répertoriés en haut de la page de manuel sous DEFINITIONS. Nous pourrions considérer ()comme des opérateurs de contrôle comme |dans le cas où les deux impliquent des sous-coquilles. Et { }fonctionne dans le shell actuel et ne peut pas impliquer de sous-shell.
glenn jackman
@Kusalananda Found it, section 2.9.2: "Si le pipeline commence par le mot réservé! Et command1 est une commande de sous-shell, l'application doit s'assurer que l'opérateur (au début de command1 est séparé du! Par un ou plusieurs < blanc> caractères. Le comportement du mot réservé! immédiatement suivi de l'opérateur (n'est pas spécifié. "Pas de définition claire mais la norme l'appelle (opérateur
Sergiy Kolodyazhnyy
@glennjackman S'il est vrai que les pipelines impliquent des sous-coquilles, ce n'est pas le type de définition qui semble approprié. La norme mentionne également que dans certaines implémentations, le pipeline peut fonctionner dans l'environnement d'exécution shell actuel (et je sais que c'est dans la norme, car j'ai vu le texte hier et le cherche maintenant). Cependant, votre suggestion m'a amené à trouver la citation que j'ai commentée ci-dessus, où au moins la norme l' appelle opérateur mais ne la définit pas explicitement comme un
Sergiy Kolodyazhnyy