Почему пробелы иногда нужны вокруг метасимволов?

531

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

bash: syntax error near unexpected token `{:'

Вчера это случилось, когда я попытался запустить его в оболочке Bash, а затем добавил добавленные пробелы, и он неожиданно сработал, :(){ :|:& };: вместо :(){:|:&};:

Имеет ли значение пробел; я сделал татуировку синтаксической ошибки на моей руке?!

Кажется, что всегда работает в zsh, но не в Bash.

Связанный вопрос не объясняет ничего о пробелах, что на самом деле является моим вопросом; Почему для Bash требуется пропустить пробел, чтобы иметь возможность правильно его разобрать?

  • 6
    Я отправил тот же вопрос здесь (исключая часть татуировки).
  • 2
    Кроме того, двоеточие (:) нельзя использовать в качестве имени функции (см. Pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) ... FreeBSD / bin / sh даже выдает ошибку ...
Показать ещё 1 комментарий
Теги:
syntax-error

5 ответов

247
Лучший ответ

Существует список символов, разделяющих токены в BASH. Эти символы называются метасимволами, а они |, &, ;, (, ), <, >, space и вкладка. С другой стороны, фигурные скобки ({ и }) являются просто обычными символами, которые составляют слова.

Опускание второго пространства до } будет выполняться, так как & является метасимволом. Поэтому ваша татуировка должна иметь по крайней мере один пробел.

:(){ :|:&};:
  • 30
    Простое решение: переместите первую часть тау влево и пересадите кожу между двумя частями.
  • 20
    Мне понравился термин, on the other hand ... каламбур предназначен? ;): D (Извините, за не по теме комментарий.)
Показать ещё 4 комментария
68

Просто татуировка

#!/bin/zsh

shebang над ним, и все будет хорошо.

  • 6
    Если мы придирчивы, шебанг не будет работать вообще, так как оболочка, надеюсь zsh, находится в интерактивном режиме, о чем свидетельствует подсказка ...
  • 0
    Тогда просто запустите команду zsh перед этим!
49

Скобки больше похожи на нечетные ключевые слова, чем специальные символы, и нужны пробелы. Например, это относится к круглым скобкам. Для сравнения:

(ls)

который работает, и:

{ls}

который ищет команду с именем {ls}. Для работы это должно быть:

{ ls; }

Точка с запятой останавливает закрытие фигурной скобки как параметр ls.

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

  • 4
    {ls,} работает однако ;-)
  • 0
    @ Да, нет, это не сложное утверждение.
Показать ещё 8 комментариев
38

Хотя это и не легко видно в шрифте тату, на самом деле есть знак байта (BOM) между фигурной скобкой и двоеточием (вы, возможно, были достаточно опьянены, когда получили тату, что вы его не заметили, но это действительно там). Это оставляет три очевидные возможности:

  • Вы не смогли ввести спецификацию при расшифровке кода. Результат - очевидное применение GIGO. Оболочка просто не распознает спецификацию, которая отсутствует в вашей неудачной транскрипции.
  • Ваша оболочка слишком стар. Он не распознает символы Юникода, поэтому спецификация (и, возможно, все остальные символы Юникода) игнорируется полностью, даже если спецификация в любом месте, кроме начала файла, считается обработанной как незаполненное пространство нулевой ширины.
  • Ваша оболочка слишком новая. Использование спецификации в качестве ZWNBS устарело, и авторы внедрили будущую версию Unicode, в которой это использование больше не разрешено.
38

а затем я добавил пробел, и он внезапно сработал...

Это из-за того, как интерпретируется оболочка. После определения функции вам понадобится пробел, т.е. После {.

foo() { echo hey& }
foo() { echo hey&}
foo(){ echo hey&}

. С другой стороны,

foo() {echo hey&}

нет.


Вам действительно нужна татуировка:

Изображение 3887


Из источник:

  /* We ignore an open brace surrounded by whitespace, and also
     an open brace followed immediately by a close brace preceded
     by whitespace.  */

Опускание пробела после { приводит к тому, что {echo интерпретируется как один токен.


Эквивалентная форма

:(){ :|:& };:

будет

:(){
:|:& };:

Обратите внимание, что в альтернативной версии нет пробела после {, но разрыв строки заставляет оболочку распознавать { как токен.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню