Perché un gruppo di comandi di parentesi graffa ha bisogno di spazi dopo il controvento di apertura in Grammatica shell POSIX?


10

TL; DR : Perché il gruppo di parentesi graffe POSIX ha bisogno di spazi dopo la {parola riservata, ma la subshell non segue la parola riservata (?

La grammatica della shell POSIX definisce il gruppo di controventi e la subshell come segue

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Ora, se lo stiamo leggendo letteralmente, gli spazi sono significativi. Ciò significherebbe che deve esserci spazio che delinea l'apertura e la chiusura di parentesi graffe e parentesi come in

{ echo hello world; }

( echo hello world )

Ciò si allinea anche con le definizioni del comando composto :

Ognuno di questi comandi composti ha una parola riservata o un operatore di controllo all'inizio e una parola riservata o un operatore terminatore corrispondente alla fine.

Tuttavia, ciò che non ha senso è perché (list)e ( list )lavorare bene (quello spazio dopo (non è necessario), tuttavia l'espansione del rinforzo deve avere uno spazio iniziale, cioè {echo hello;}non funzionerebbe.

Naturalmente la parola riservata che viene trattata come parola shell avrebbe senso avere bisogno di uno spazio in seguito per allinearsi con il concetto di divisione del campo , tuttavia la definizione stessa non fa menzione di spazi. Inoltre, se {e (entrambi sono considerati parole riservate dalla definizione POSIX di comando composto, perché vengono trattati in modo diverso rispetto al carattere dello spazio dopo queste parole riservate? Ora, il manuale di ksh (1) afferma:

Le parole, che sono sequenze di caratteri, sono delimitate da caratteri di spazi bianchi non quotati (spazio, tabulazione e nuova riga) o meta-caratteri (<,>, |,;, &, (e))

In altre parole, ha senso che ksh riconoscesse (come delimitatore di parole, dove la prima parola sarebbe un comando o un'assegnazione variabile. POSIX, tuttavia, non sembra menzionare (come meta-personaggio. L'unica spiegazione possibile che ho trovato per quanto riguarda la grammatica POSIX è che {è considerato un "token", dove (non è elencato come uno.

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


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

Quindi quale sarebbe il ragionamento preciso per questa discrepanza?

Note di risposta accettate:

  • Sposta il segno di spunta accettato nella risposta di Isaac poiché fornisce q uote dallo standard stesso che risponde direttamente alla mia domanda:

    Ad esempio, "(" e ")" sono operatori di controllo, quindi non <space>è necessario in (elenco). Tuttavia, "{" e "}" sono parole riservate in {list;}, quindi in questo caso il comando iniziale <space>e <semicolon>sono obbligatori.

  • Accettare la risposta di Kusalananda . La risposta di Kusalananda si rivolge a ciò di cui avevo bisogno, anche se principalmente dal punto di vista informale e intuitivo; indica {una parola riservata ed (è operatore. Anche Michael Homer ha notato lo stesso nei commenti - che la definizione di Comando composto afferma (enfasi aggiunta):

    Ognuno di questi comandi composti ha una parola riservata o un operatore di controllo all'inizio

  • {sono definiti come parole riservate, simili a foro while, elencate in Shell Grammar (vedere l'ultimo blocco di codice nella domanda)

  • La sezione 2.9 afferma (enfasi aggiunta):

    In particolare, le rappresentazioni includono la spaziatura tra i token in alcuni punti dove <blank>s non sarebbe necessario (quando uno dei token è un operatore).

  • Mentre lo standard non definisce esplicitamente (come operatore, (viene indicato come operatore; in particolare, dice la sezione 2.9.2

    Se la pipeline inizia con la parola riservata! e command1 è un comando subshell, l'applicazione deve assicurarsi che l'operatore (all'inizio del comando1 sia separato da! da uno o più caratteri. Il comportamento della parola riservata! immediatamente seguito dall'operatore (non è specificato.

  • La domanda su Stack Overflow di Digital Trauma sottolinea la Sezione 2.4 sulle parole riservate:

    Questo riconoscimento deve avvenire solo quando nessuno dei caratteri è citato e quando la parola è usata come:

    -La prima parola di un comando

  • Come menzionato nella risposta di Kusalananda "Gli spazi mostrati nella grammatica POSIX non sono spazi che devono essere presenti nei dati di input della shell, ma solo un modo per visualizzare la grammatica stessa. È il fatto che le parentesi graffe sono parole riservate che implica che devono essere circondati da spazi bianchi "Come menzionato da Michael Homer nei commenti:" Se gli spazi fossero significativi di per sé, avrebbero bisogno di essere elencati nella produzione "

Caso chiuso.


3
Se gli spazi fossero significativi di per sé, dovrebbero essere elencati nella produzione.
Michael Homer,

2
"Inoltre, se {e (sono entrambi considerati parole riservate dalla definizione POSIX del comando composto" cfr. "Ciascuno di questi comandi composti ha una parola riservata o un operatore di controllo all'inizio".
Michael Homer,

2
@SergiyKolodyazhnyy Credo che significhi che se lo spazio fosse significativo, la grammatica avrebbe dovuto includere un carattere spazio esplicito ( ' '). Invece, gli spazi sono impliciti da ciò che i token sono parole.
Kusalananda

2
La definizione delle specifiche della classe token è ... a dir poco imbarazzante. L'intera grammatica è piuttosto terribile e le specifiche mescolano la definizione delle cose in prosa nel testo (a volte implicitamente!), Nelle regole di prosa che precedono la grammatica e nella grammatica stessa. È piuttosto incomprensibile se non si conosce già la risposta e si lavora all'indietro. Le regole lessicali sono tutte definite al contrario, da ciò che inizia un nuovo token, piuttosto che descrivere cosa contiene il token. È solo un casino tutto intorno.
Michael Homer,

1
@Sergiy in grammatica formale, una produzione (o regola di produzione) descrive come puoi generare qualcosa da qualcos'altro. Vedi en.wikipedia.org/wiki/Production_%28computer_science%29 Quindi command : simple_command | compound_command | compound_command redirect_list | function_definition ;è una produzione che dice dove puoi avere un comando, può essere uno di comando semplice, comando composto o comando composto con reindirizzamento o una definizione di funzione.
Muru,

Risposte:


6

Questa è una limitazione del modo in cui la shell spezza le linee in token.

La shell legge le righe dal file di input e secondo la sezione 2 "Introduzione alla shell" le converte in una parola o in un operatore :

  1. La shell suddivide l'input in token: parole e operatori

{è una parola riservata

Alcune parole sono parole riservate

Le parole riservate sono parole che hanno un significato speciale per la shell. Le seguenti parole devono essere riconosciute come parole riservate:

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

Le parole, per essere riconosciute come parole, devono essere delimitate .

Le parole riservate vengono riconosciute solo quando sono delimitate ...

Principalmente per spazi vuoti (punto 7) e per operatori.

  1. Se il personaggio corrente è un <blank> non quotato, qualsiasi token contenente il personaggio precedente viene delimitato e il personaggio corrente deve essere scartato.

(è un operatore

Gli operatori stanno da soli :

mentre gli operatori sono essi stessi delimitatori.

Dove "operatori" sono :

3.260 Operatore

Nel linguaggio dei comandi della shell, un operatore di controllo o un operatore di reindirizzamento .

Gli operatori di reindirizzamento sono :

Operatore di reindirizzamento

Nel linguaggio dei comandi della shell, un token che esegue una funzione di reindirizzamento. È uno dei seguenti simboli:

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

Gli operatori di controllo sono :

3.113 Operatore di controllo

Nel linguaggio dei comandi della shell, un token che esegue una funzione di controllo. È uno dei seguenti simboli:

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

Conclusione

Quindi, '(' e ')' sono operatori di controllo mentre '{' '}' sono parole riservate.

E la stessa descrizione esatta della tua domanda è all'interno della specifica :

Ad esempio, '(' e ')' sono operatori di controllo, quindi non è necessario <spazio> in (elenco). Tuttavia, "{" e "}" sono parole riservate in {list;}, quindi in questo caso sono richiesti <space> e <semicolon>.

Il che spiega esattamente perché uno spazio (o qualche altro delimitatore) è richiesto dopo a {.

Questo è valido:

{ echo yes;}

Come è questo:

{(echo yes);}

Questo:

{(echo yes)}

O anche questo:

{>/dev/tty echo yes;}

Bene, l'ultima citazione è esattamente perfetta! Fatto +1. Devo rivedere la domanda e le risposte ora
Sergiy Kolodyazhnyy,

13

La differenza tra le parentesi e le parentesi sono che le parentesi (e !) sono parole riservate, come for, if, thenecc mentre parentesi sono operatori di controllo. Le parole devono essere separate da spazi bianchi.

Ciò significa che proprio come non puoi avere

foriin*; do

non puoi avere

{somecommand;} >file

o

if !somecommand; then

Gli spazi mostrati nella grammatica POSIX non sono spazi che devono essere presenti nei dati di input della shell, ma solo un modo per visualizzare la grammatica stessa. È il fatto che le parentesi graffe sono parole riservate, il che implica che devono essere circondate da spazi bianchi, mentre le parentesi di una subshell no.


1
Bene, questo sembra praticamente rispondere e vedo che dice "In particolare, le rappresentazioni includono la spaziatura tra i token in alcuni punti in cui <blank> s non sarebbe necessario (quando uno dei token è un operatore)". Solo una domanda: dove lo standard definisce (operatore? Almeno non è nella sezione grammaticale
Sergiy Kolodyazhnyy il

@MichaelHomer Ah, "operatore di controllo", proprio come ;. Grazie per quello
Kusalananda

Gli operatori di controllo sono elencati nella parte superiore della pagina man sotto DEFINIZIONI. Potremmo considerare ()come operatori di controllo come |in entrambi implicano sottotitoli. E { }funziona nella shell corrente e non può coinvolgere una subshell.
Glenn Jackman,

@Kusalananda Lo ha trovato, sezione 2.9.2: "Se la pipeline inizia con la parola riservata! E command1 è un comando subshell, l'applicazione deve assicurare che l'operatore (all'inizio del comando1 sia separato da! Da uno o più < caratteri> vuoti. Il comportamento della parola riservata! immediatamente seguito da (l'operatore non è specificato. "Non una definizione chiara ma lo standard lo chiama (operatore
Sergiy Kolodyazhnyy

@glennjackman Anche se è vero che le pipeline coinvolgono i subshells, questo non è il tipo di definizione che sembra appropriato. Lo standard menziona anche che in alcune implementazioni è OK eseguire la pipeline nell'attuale ambiente di esecuzione della shell (e so che è nello standard, perché ieri ho visto il testo e lo sto cercando ora). Tuttavia, il tuo suggerimento mi ha suggerito di trovare la citazione che ho commentato sopra, dove almeno lo standard lo chiama operatore ma non lo definisce esplicitamente come uno
Sergiy Kolodyazhnyy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.