Зачем группе команд скобки нужны пробелы после открывающей скобки в POSIX Shell Grammar?

10

TL; DR : Почему группе скобок POSIX нужны пробелы после {зарезервированного слова, а в подоболочке нет после зарезервированного слова (?

Грамматика оболочки POSIX определяет группу скобок и подоболочку следующим образом

brace_group      : Lbrace compound_list Rbrace

subshell         : '(' compound_list ')'

Теперь, если мы читаем это буквально, пробелы важны. Это будет означать, что должно быть пространство, обозначающее открывающую и закрывающую скобки и скобки, как в

{ echo hello world; }

( echo hello world )

Это также будет соответствовать определениям составных команд :

Каждая из этих составных команд имеет зарезервированное слово или оператор управления в начале и соответствующее зарезервированное слово или оператор терминатора в конце.

Однако то, что не имеет смысла, так это то, почему (list)и ( list )работают просто отлично (это место после (не требуется), однако расширение скобки должно иметь начальное пространство, то есть {echo hello;}не будет работать.

Конечно, зарезервированное слово, рассматриваемое как слово оболочки, будет иметь смысл, если впоследствии потребуется место для выравнивания с концепцией разбиения поля , однако само определение не упоминает пробелы. Кроме того, если {и (оба считаются зарезервированными словами , по определению POSIX соединения команды, поэтому они рассматриваются по- разному в отношении космического характера после этих зарезервированных слов? Теперь руководство ksh (1) заявляет:

Слова, являющиеся последовательностями символов, отделяются символами пробела без кавычек (пробел, табуляция и новая строка) или метасимволами (<,>, |,;, &, (и))

Другими словами, имеет смысл, что ksh будет распознавать (как разделитель слов, где первое слово будет назначением команды или переменной. POSIX, однако, не упоминается (как метасимвол. Единственное возможное объяснение, которое я нашел в отношении грамматики POSIX, - это то, что {он считается «токеном», где (он не указан как единое целое.

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


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

Так, что было бы точным обоснованием этого несоответствия?

Принятый ответ Примечания:

  • В ответ на вопрос Исаака перенесена принятая галочка , поскольку он предоставляет саму форму стандарта , которая непосредственно касается моего вопроса:

    Например, '(' и ')' являются управляющими операторами, поэтому нет <space>необходимости в (list). Однако '{' и '}' являются зарезервированными словами в {list;}, так что в этом случае ведущие <space>и <semicolon>обязательные.

  • Принимая ответ Кусалананды . Ответ Кусалананды касается того, что мне было нужно, хотя в основном с неформальной и интуитивной точки зрения; оно указывает {на зарезервированное слово и (является оператором. Майкл Гомер также отметил в комментариях то же самое - это определение составной команды (выделение добавлено):

    Каждая из этих составных команд имеет зарезервированное слово или оператор управления в начале

  • {определяются как зарезервированное слово, подобное forили while, перечисленное в грамматике оболочки (см. последний блок кода в вопросе)

  • Раздел 2.9 гласит (выделено):

    В частности, представления включают в себя расстояние между токенами в некоторых местах, где <blank>s не требуется (когда один из токенов является оператором).

  • Хотя стандарт явно не определяет (оператор, (он называется оператором; в частности, в разделе 2.9.2 говорится

    Если конвейер начинается с зарезервированного слова! и command1 - команда subshell, приложение должно гарантировать, что оператор (в начале команды command1 отделяется от! одним или несколькими символами. Поведение зарезервированного слова!, за которым сразу следует оператор (, не определено.

  • Вопрос о переполнении стека цифровой травмой указывает на раздел 2.4 о зарезервированных словах:

    Это распознавание должно происходить только тогда, когда ни один из символов не указан в кавычках и когда слово используется как:

    -Первое слово команды

  • Как упоминалось в ответе Кусалананды: «Пробелы, показанные в грамматике POSIX, - это не пробелы, которые должны присутствовать во входных данных оболочки, а просто способ отображения самой грамматики. Это тот факт, что фигурные скобки являются зарезервированными словами, что подразумевает, что они должны быть окружены пробелами "Как упоминал Майкл Гомер в комментариях:" Если бы места были сами по себе значительными, их нужно было бы включить в производство "

Дело закрыто.

Сергей Колодяжный
источник
3
Если бы места были значительными сами по себе, их нужно было бы перечислить в производстве.
Майкл Гомер
2
«Кроме того, если {и (оба считаются зарезервированными словами по определению составной команды POSIX», см. «Каждая из этих составных команд имеет зарезервированное слово или оператор управления в начале».
Майкл Гомер
2
@SergiyKolodyazhnyy Я полагаю, он имеет в виду, что если бы пробел был значительным, грамматика должна была бы включать явный пробел ( ' '). Вместо этого пробелы подразумеваются тем, что токены являются словами.
Кусалананда
2
Определение спецификации класса токенов ... по меньшей мере, неудобно. Вся грамматика довольно ужасна, и спецификация смешивает определяющие вещи в тексте прозы (иногда неявно!), В правилах прозы, предшествующих грамматике, и в самой грамматике. Это довольно непонятно, если вы еще не знаете ответ и работаете задом наперед. Все лексические правила определяются задом наперед, начиная с того, что начинает новый токен, а не с описания того, что этот токен содержит. Это просто беспорядок вокруг.
Майкл Гомер
1
@Sergiy в формальной грамматике, производство (или правило производства) описывает, как вы можете генерировать что-то из чего-то другого. См. En.wikipedia.org/wiki/Production_%28computer_science%29. Итак command : simple_command | compound_command | compound_command redirect_list | function_definition ;, это постановка, в которой говорится, где вы можете иметь команду, это может быть простая команда, составная команда или составная команда с перенаправлением или определение функции.
Муру

Ответы:

6

Это ограничение способа, которым оболочка разбивает строки на токены.

Оболочка считывает строки из входного файла и в соответствии с разделом 2 «Введение в оболочку» преобразует их в слово или оператор :

  1. Оболочка разбивает входные данные на токены: слова и операторы

{это зарезервированное слово

Некоторые слова являются зарезервированными словами

Зарезервированные слова - это слова, которые имеют особое значение для оболочки. Следующие слова должны быть распознаны как зарезервированные слова:

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

Слова, которые должны распознаваться как слова, должны быть разделены .

Зарезервированные слова распознаются только тогда, когда они разделены ...

В основном по пробелам (пункт 7) и по операторам.

  1. Если текущим символом является <пробел> без кавычек, любой токен, содержащий предыдущий символ, отделяется, а текущий символ должен быть отброшен.

(является оператором

Операторы стоят сами за себя :

тогда как операторы сами являются разделителями.

Где «операторы» :

3.260 Оператор

На языке команд оболочки - либо управляющий оператор , либо оператор перенаправления .

Операторы перенаправления :

Оператор перенаправления

На языке команд оболочки - токен, выполняющий функцию перенаправления. Это один из следующих символов:

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

Управляющие операторы :

3.113 Оператор Управления

На языке команд оболочки - токен, который выполняет функцию управления. Это один из следующих символов:

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

Вывод

Таким образом, '(' и ')' являются управляющими операторами, а '{' '}' являются зарезервированными словами.

И точно такое же описание вашего вопроса находится внутри спецификации :

Например, '(' и ')' являются управляющими операторами, поэтому <space> не требуется в (list). Однако '{' и '}' являются зарезервированными словами в {list;}, поэтому в этом случае требуются начальные <пробел> и <точка с запятой>.

Что точно объясняет, почему после a требуется пробел (или какой-либо другой разделитель) {.

Это действительно:

{ echo yes;}

Как это:

{(echo yes);}

Эта:

{(echo yes)}

Или даже это:

{>/dev/tty echo yes;}
Исаак
источник
Ну, последняя цитата точно на месте! Добавили +1. Мне нужно будет рассмотреть вопрос и ответы сейчас
Сергей Колодяжный
13

Разница между фигурными скобками и скобками в том , что фигурные скобки (и !) являются зарезервированными словами, так же , как for, if, и thenт.д. , а Скобки операторы управления. Слова должны быть разделены пробелами.

Это означает, что так же, как вы не можете иметь

foriin*; do

ты не можешь иметь

{somecommand;} >file

или

if !somecommand; then

Пробелы, показанные в грамматике POSIX, - это не пробелы, которые должны присутствовать во входных данных оболочки, а просто способ отображения самой грамматики. Тот факт, что фигурные скобки являются зарезервированными словами , означает, что они должны быть окружены пробелами, а скобки подоболочки - нет.

Кусалананда
источник
1
Что ж, похоже, это в значительной степени отвечает на это, и я вижу, что оно говорит: «В частности, представления включают в себя интервалы между токенами в некоторых местах, где <blank> не понадобятся (когда один из токенов является оператором)». Только один вопрос: где стандарт определяется (как оператор? По крайней мере, в разделе грамматики
Сергей Колодяжный
@MichaelHomer Ах, "оператор управления", как и все ;. Спасибо за это.
Кусалананда
Операторы управления перечислены в верхней части справочной страницы в разделе ОПРЕДЕЛЕНИЯ. Мы могли бы посмотреть на ()управляющие операторы, подобные |тем, что оба включают в себя подоболочки. И { }работает в текущей оболочке и не может включать в себя подоболочку.
Гленн Джекман
@Kusalananda Нашел его, раздел 2.9.2: «Если конвейер начинается с зарезервированного слова! И команда1 является командой подоболочки, приложение должно гарантировать, что оператор (в начале команды1 отделен от! Одним или несколькими < пробел> символов. Поведение зарезервированного слова!, сразу после которого следует оператор (оператор не (
Сергей Колодяжный
@glennjackman Хотя верно, что конвейеры включают в себя подоболочки, это не тот тип определения, который кажется подходящим. В стандарте также упоминается, что в некоторых реализациях нормально работать с конвейером в текущей среде выполнения оболочки (и я знаю, что это в стандарте, потому что я вчера видел текст и искал его сейчас). Тем не менее, ваше предложение действительно указывало на то, что я нашел цитату, которую я прокомментировал выше, где по крайней мере стандарт действительно называет это оператором, хотя явно не определяет его как единое целое
Сергей Колодяжный