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

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

bash: syntax error near unexpected token `{:'

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

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

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

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

Ответ 1

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

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

:(){ :|:&};:

Ответ 2

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

#!/bin/zsh

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

Ответ 3

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

(ls)

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

{ls}

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

{ ls; }

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

foo() {echo hey&}

нет.


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

enter image description here


Из источник:

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

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


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

:(){ :|:& };:

будет

:(){
:|:& };:

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