¿Por qué un grupo de comandos de llaves necesita espacios después de la llave de apertura en POSIX Shell Grammar?

10

TL; DR : ¿Por qué el grupo de llaves POSIX necesita espacios después de la {palabra reservada pero la subshell no necesita después de la palabra reservada (?

La gramática del shell POSIX define el grupo de llaves y el subshell de la siguiente manera

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Ahora, si estamos leyendo eso literalmente, los espacios son significativos. Esto significaría que debe haber un espacio que delimite la llave de apertura y cierre y el paréntesis como en

{ echo hello world; }

( echo hello world )

Esto también se alinearía con las definiciones de Compound Command :

Cada uno de estos comandos compuestos tiene una palabra reservada u operador de control al principio, y una palabra u operador reservado terminador correspondiente al final.

Sin embargo, lo que no tiene sentido es por qué (list)y ( list )funciona bien (ese espacio después (no es necesario), sin embargo, la expansión de llaves debe tener un espacio principal, es decir {echo hello;}, no funcionaría.

Por supuesto, la palabra reservada que se trata como palabra shell tendría sentido necesitar un espacio para alinearse con el concepto de división de campo , sin embargo, la definición en sí misma no menciona los espacios. Además, si {y (son dos palabras reservadas considerado por POSIX definición de orden compuesta, ¿por qué se les trata de manera diferente en lo que respecta al carácter de espacio después de estas palabras reservadas? Ahora, el manual ksh (1) dice:

Las palabras, que son secuencias de caracteres, están delimitadas por espacios en blanco sin comillas (espacio, tabulación y nueva línea) o metacaracteres (<,>, |,;, &, (y))

En otras palabras, tiene sentido que ksh reconozca (como delimitador de palabras, donde la primera palabra sería un comando o una asignación variable. POSIX, sin embargo, no parece mencionarlo (como meta-personaje. La única explicación posible que encontré en lo que respecta a la gramática POSIX es que {se considera un "token", donde (no figura como uno.

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


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

Entonces, ¿cuál sería un razonamiento preciso para esta discrepancia?

Notas de respuesta aceptadas:

  • Moved aceptó la marca de verificación a la respuesta de Isaac, ya que proporciona q uote forma el estándar en sí que aborda directamente mi pregunta:

    Por ejemplo, '(' y ')' son operadores de control, por lo que no <space>se necesita ninguno en (lista). Sin embargo, '{' y '}' son palabras reservadas en {list;}, por lo que, en este caso, son las iniciales <space>y <semicolon>son obligatorias.

  • Aceptando la respuesta de Kusalananda . La respuesta de Kusalananda aborda lo que necesitaba, aunque principalmente desde un punto de vista informal e intuitivo; señala que {es una palabra reservada y (es operador. Michael Homer también notó lo mismo en los comentarios: la definición del Comando Compuesto establece (énfasis agregado):

    Cada uno de estos comandos compuestos tiene una palabra reservada o un operador de control al principio

  • {se definen como palabras reservadas, similares foro whileenumeradas en la gramática de Shell (consulte el último bloque de código en la pregunta)

  • La sección 2.9 establece (énfasis agregado):

    En particular, las representaciones incluyen el espacio entre tokens en algunos lugares donde <blank>s no sería necesario (cuando uno de los tokens es un operador).

  • Si bien el estándar no se define explícitamente (como un operador, (se conoce como operador; específicamente, la sección 2.9.2 dice

    Si la tubería comienza con la palabra reservada! y command1 es un comando subshell, la aplicación se asegurará de que el operador (al comienzo del comando1 esté separado del! por uno o más caracteres. El comportamiento de la palabra reservada! inmediatamente seguido por el operador (no está especificado.

  • La pregunta sobre desbordamiento de pila por trauma digital señala la sección 2.4 sobre palabras reservadas:

    Este reconocimiento solo ocurrirá cuando no se cite ninguno de los caracteres y cuando la palabra se use como:

    -La primera palabra de un comando

  • Como se menciona en la respuesta de Kusalananda "Los espacios que se muestran en la gramática POSIX no son espacios que deben estar allí en los datos de entrada del shell, sino solo una forma de mostrar la gramática en sí. Es el hecho de que los corchetes son palabras reservadas que implica que tienen que estar rodeados de espacios en blanco "Como mencionó Michael Homer en los comentarios:" Si los espacios fueran significativos por derecho propio, tendrían que estar incluidos en la producción "

Caso cerrado.

Sergiy Kolodyazhnyy
fuente
3
Si los espacios fueran significativos por derecho propio, tendrían que estar incluidos en la producción.
Michael Homer
2
"Además, si {y (son dos palabras reservadas considerado por POSIX definición de orden compuesta" cf. "Cada uno de estos comandos compuestos tiene una palabra reservada o un operador de control al principio".
Michael Homer
2
@SergiyKolodyazhnyy Creo que quiere decir que si el espacio fuera significativo, la gramática habría tenido que incluir un carácter de espacio explícito ( ' '). En cambio, los espacios están implicados por qué tokens son palabras.
Kusalananda
2
La definición de especificación de la clase de token es ... incómoda, por decir lo menos. Toda la gramática es bastante terrible y la mezcla de especificaciones define las cosas en prosa en el texto (¡a veces implícitamente!), En las reglas en prosa que preceden a la gramática y en la gramática misma. Es bastante incomprensible si aún no sabes la respuesta y trabajas al revés. Todas las reglas léxicas se definen al revés, por lo que comienza un nuevo token, en lugar de describir lo que contiene el token. Es solo un desastre por todas partes.
Michael Homer
1
@Sergiy en gramática formal, una producción (o regla de producción) describe cómo puede generar algo a partir de otra cosa. Ver en.wikipedia.org/wiki/Production_%28computer_science%29 Entonces, command : simple_command | compound_command | compound_command redirect_list | function_definition ;es una producción que dice dónde puede tener un comando, puede ser un comando simple, un comando compuesto o un comando compuesto con redirección, o una definición de función.
muru

Respuestas:

6

Esa es una limitación de la forma en que el shell divide las líneas en tokens.

El shell lee líneas del archivo de entrada y, según la sección 2, "Introducción al shell", las convierte en una palabra o en un operador :

  1. El shell divide la entrada en tokens: palabras y operadores.

{es una palabra reservada

Algunas palabras son palabras reservadas

Las palabras reservadas son palabras que tienen un significado especial para el shell. Las siguientes palabras se reconocerán como palabras reservadas:

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

Las palabras, para ser reconocidas como palabras, deben delimitarse .

Las palabras reservadas se reconocen solo cuando están delimitadas ...

Principalmente por espacios en blanco (punto 7) y por operadores.

  1. Si el carácter actual es un <blank> sin comillas, cualquier ficha que contenga el carácter anterior se delimitará y el carácter actual se descartará.

(es un operador

Los operadores se mantienen solos :

mientras que los operadores son en sí mismos delimitadores.

Donde "operadores" son :

3.260 Operador

En el lenguaje de comandos de shell, ya sea un operador de control o un operador de redireccionamiento .

Los operadores de redireccionamiento son :

Operador de redireccionamiento

En el lenguaje de comandos de shell, un token que realiza una función de redireccionamiento. Es uno de los siguientes símbolos:

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

Los operadores de control son :

3.113 Operador de control

En el lenguaje de comandos de shell, un token que realiza una función de control. Es uno de los siguientes símbolos:

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

Conclusión

Entonces, '(' y ')' son operadores de control, mientras que '{' '}' son palabras reservadas.

Y la misma descripción exacta de su pregunta está dentro de la especificación :

Por ejemplo, '(' y ')' son operadores de control, por lo que no se necesita <space> en (list). Sin embargo, '{' y '}' son palabras reservadas en {list;}, por lo que en este caso se requieren los <space> y <semicolon> iniciales.

Lo que explica exactamente por qué se requiere un espacio (o algún otro delimitador) después de a {.

Esto es valido:

{ echo yes;}

Como es esto:

{(echo yes);}

Esta:

{(echo yes)}

O incluso esto:

{>/dev/tty echo yes;}
Isaac
fuente
Bueno, ¡la última cita es exactamente acertada! + 1'ed. Tendré que revisar la pregunta y las respuestas ahora
Sergiy Kolodyazhnyy
13

La diferencia entre las llaves y los paréntesis son que los apoyos (y !) son palabras reservadas, al igual que for, if, thenetc, mientras que entre paréntesis son los operadores de control. Las palabras deben estar separadas por espacios en blanco.

Esto significa que al igual que no puedes tener

foriin*; do

no puedes tener

{somecommand;} >file

o

if !somecommand; then

Los espacios que se muestran en la gramática POSIX no son espacios que deben estar allí en los datos de entrada del shell, sino solo una forma de mostrar la gramática en sí. Es el hecho de que los corchetes son palabras reservadas lo que implica que tienen que estar rodeados de espacios en blanco, mientras que los paréntesis de un subshell no.

Kusalananda
fuente
1
Bueno, esto parece responderlo y veo que dice "En particular, las representaciones incluyen el espaciado entre tokens en algunos lugares donde <blank> s no serían necesarios (cuando uno de los tokens es un operador)". Solo una pregunta: ¿dónde se define el estándar (como operador? No está en la sección de gramática al menos
Sergiy Kolodyazhnyy
@MichaelHomer Ah, "operador de control", al igual que ;. Gracias por eso.
Kusalananda
Los operadores de control se enumeran en la parte superior de la página de manual en DEFINICIONES. Podríamos considerar ()como operadores de control, ya |que ambos implican subcapas. Y { }funciona en el shell actual y no puede involucrar un subshell.
Glenn Jackman
@Kusalananda Lo encontró, sección 2.9.2: "¡Si la tubería comienza con la palabra reservada! Y command1 es un comando subshell, la aplicación se asegurará de que el (operador al comienzo del comando1 esté separado del! Por uno o más < en blanco> caracteres. El comportamiento de la palabra reservada! inmediatamente seguido por el operador (no está especificado. "No es una definición clara pero el estándar lo llama (operador
Sergiy Kolodyazhnyy
@glennjackman Si bien es cierto que las tuberías involucran subcapas, ese no es el tipo de definición que parece apropiado. El estándar también menciona que en algunas implementaciones está bien que la tubería se ejecute en el entorno de ejecución de shell actual (y sé que está en el estándar, porque ayer vi el texto y lo busqué ahora). Sin embargo, su sugerencia me indicó que encontrara la cita que comenté anteriormente, donde al menos el estándar lo llama operador, aunque no lo define explícitamente como uno
Sergiy Kolodyazhnyy