Ответ 1
Потому что {
и }
распознаются только как специальный синтаксис, если они являются первым словом в команде.
Здесь есть два важных момента, оба из которых находятся в разделе определений руководства bash. Во-первых, это список метасимволов:
metacharacter
Символ, который при некорректности разделяет слова. Метасимволом является пустой или один из следующих символов: '|,' &, ';,' (, '),' <, или ' > .
Этот список содержит круглые скобки, но не фигурные скобки (ни курчавые, ни квадратные). Обратите внимание, что это не полный список символов со специальным значением для оболочки, но это полный список символов, разделяющих токены. Таким образом, {
и }
не разделяют токены и будут считаться только самими токенами, если они смежны с метасимволом, например пробелом или точкой с запятой.
Хотя фигурные скобки не являются метасимволами, они обрабатываются специально оболочкой в расширении параметров (например, ${foo}
) и расширение брекета (например, foo.{c,h}
). Кроме этого, они просто нормальные персонажи. Нет проблем с именованием файла {ab}
, например, или }{
, поскольку эти слова не соответствуют синтаксису разложения параметра (для которого требуется $
до {
) или расширения брекета ( которая требует по крайней мере одной запятой между {
и }
). В этом случае вы можете использовать {
или }
в качестве имени файла, не указывая при этом символы. Аналогичным образом вы можете вызвать файл 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
):
Это распознавание [как зарезервированное слово] происходит только тогда, когда ни один из символов не цитируется, и когда слово используется как:
- Первое слово команды & hellip;
(Полный список мест, где распознаются зарезервированные слова, немного длиннее, но выше это довольно хорошее резюме). Другими словами, зарезервированные слова зарезервированы только в том случае, если они являются первым словом команды. И, поскольку {
и }
являются зарезервированными словами, они являются только специальным синтаксисом, если они являются первым словом в команде.
Пример:
ls } # } is not a reserved word. It is an argument to `ls`
ls;} # } is a reserved word; `ls` has no arguments
Есть много больше, о которых я мог бы написать о разборе синтаксиса, а в частности, о синтаксисе bash, но он быстро стал бы утомительным. (Например, правило о том, когда #
начинает комментарий и когда это обычный символ). Примерное резюме: "не пытайтесь это дома"; действительно, единственное, что может анализировать команды оболочки, это оболочка. И не пытайтесь разобраться в этом: это просто случайная коллекция произвольных выборов и исторических аномалий, многие, но не все, основанные на необходимости не разрушать старые сценарии оболочки с новыми функциями.