группы команд bash: почему фигурные скобки требуют точки с запятой?

Я знаю разницу в назначении между скобками () и фигурные скобки {}, когда группировка команд в bash.

но почему для конструкции фигурной скобки требуется точка с запятой после последней команды, тогда как для конструкции круглых скобок точка с запятой является необязательной?

$ while false; do ( echo "Hello"; echo "Goodbye"; ); done
$ while false; do ( echo "Hello"; echo "Goodbye" ); done
$ while false; do { echo "Hello"; echo "Goodbye"; }; done
$ while false; do { echo "Hello"; echo "Goodbye" }; done
bash: syntax error near unexpected token `done'
$ 

Я ищу некоторое представление о том, почему это так. Я не ищу ответы, такие как "потому что так написано в документации" или "потому что он был разработан таким образом". Я хотел бы знать почему он был разработан таким образом. А может, это просто исторический артефакт?

Это можно наблюдать, по крайней мере, в следующих версиях Баш:

  • в GNU bash, начиная с версии 3.00.15(1)-релиз (архитектуру x86_64-RedHat, в-линукс-гну)
  • GNU bash, версия 3.2.48 (1)-release (x86_64-apple-darwin12)
  • GNU bash, версия 4.2.25 (1)-release (x86_64-pc-linux-gnu)

1 ответов


, потому что { и } распознаются как специальный синтаксис, только если они являются первым словом в команде.


здесь есть два важных момента, оба из которых находятся в раздел определений руководства bash. Во-первых, это список метасимволы:

metacharacter

символ, который при отсутствии кавычек разделяет слова. Метасимвол - это пустой или один из следующих символов: ‘|’, ‘&’, ‘;’, ‘(’, ‘)’, ‘".

этот список включает скобки, но не фигурные скобки (ни фигурные, ни квадратные). Обратите внимание, что это не полный список символов со специальным значением для оболочки, но это полный список символов, которые отдельные лексемы. Так что { и } не разделяйте токены и будут рассматриваться только сами токены, если они находятся рядом с metacharacter, как космос или semi-двоеточие.

хотя скобки не являются метасимволами, они обрабатываются специально оболочкой в расширения параметр (напр. ${foo}) и фигурные скобки (напр. foo.{c,h}). В остальном они просто обычные люди. Нет проблем с именем файла {ab}, например, или }{, так как эти слова не соответствуют синтаксису любого расширения параметра (которое требует $ перед the {) или расширение скобки (для чего требуется хотя бы одна запятая между { и }). Если на то пошло, вы могли бы использовать { или } как имя файла без необходимости цитировать символы. Аналогично, вы можете вызвать файл if, done или time без необходимости думать о цитировании имени.

эти последние маркеры являются "зарезервированными словами":

reserved word

слово, которое имеет особое значение для оболочки. Большинство зарезервированных слов вводят конструкции управления потоком оболочки, такие как for и while.

руководство bash не содержит полного списка зарезервированных слов, что, к сожалению, но они, безусловно, включают Posix-обозначенный:

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

а также расширения, реализованные bash (и некоторыми другими оболочками):

[[   ]]
function  select time

эти слова не совпадают со встроенными (например , [), потому что они на самом деле являются частью синтаксиса оболочки. Встроенные модули могут быть реализованы как функции или сценарии оболочки, но зарезервированные слова не могут, поскольку они изменяют способ синтаксического анализа командной строки.

есть одна очень важная особенность зарезервированных слов, которая на самом деле не выделена в руководстве bash, но сделана очень явной в в POSIX (из которого были взяты вышеупомянутые списки зарезервированных слов, за исключением time):

это распознавание [как зарезервированное слово] должно происходить только тогда, когда ни один из символов не цитируется и когда слово используется как:

  • первое слово команды ...

(полный список мест, где зарезервированные слова распознаются немного длиннее, но выше довольно хорошее резюме.) Другими словами, зарезервированные слова зарезервированы только тогда, когда они первое слово команда. И, поскольку { и } являются зарезервированными словами, они являются только специальным синтаксисом, если они являются первым словом в команде.

пример:

ls }  # } is not a reserved word. It is an argument to `ls`
ls;}  # } is a reserved word; `ls` has no arguments

есть еще много чего, что я мог бы написать о разборе оболочки и разборе bash в частности, но это быстро станет утомительным. (Например, правило о том, когда # начинает комментарий, и когда это просто обычный символ.) Приблизительное резюме: "не пытайтесь это дома"; действительно, единственное, что может анализировать команды оболочки, - это оболочка. И не пытайтесь понять это: это просто случайная коллекция произвольных выборов и исторических аномалий, многие, но не все, основанные на необходимости не ломать древние сценарии оболочки с новыми функциями.