Почему иногда требуется пробел вокруг метасимволов?
Несколько месяцев назад я татуировал вилку бомбы на моей руке, и я пропустил пробелы, потому что я думаю, что они выглядят лучше без них. Но, к моему ужасу, иногда (не всегда), когда я запускаю его в оболочке, он не запускает вилку, но он просто дает синтаксическую ошибку.
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
интерпретируется как один токен.
Эквивалентная форма
:(){ :|:& };:
будет
:(){
:|:& };:
Обратите внимание, что в альтернативной версии нет пробела после {
, но разрыв строки заставляет оболочку распознавать {
как токен.