Чому іноді потрібен пробіл навколо метахарактерів?


543

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

bash: syntax error near unexpected token `{:'

Вчора це сталося, коли я спробував запустити його в другій шкаралупі Bash , а потім я додав пробіл, і це раптом спрацювало, :(){ :|:& };:а не:(){:|:&};:

Чи має значення пробіл; чи я татуював синтаксичну помилку на руці ?!

Здається, завжди працює в zsh , але не в Bash.

Пов'язане запитання нічого не пояснює про білі простори, що насправді є моїм питанням; Чому потрібен пробіл, щоб Bash міг правильно розбирати його?


6
Я відправив той же питання тут ( за винятком татуювання частини).
Бенуа

3
Також двокрапка (:) не може використовуватися як назва функції (див .: pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) ... FreeBSD's / bin / sh навіть видає помилку на цьому ...
Мартін Турноїй

5
@Carpetsmoker: Я не впевнений, наскільки це актуально. Це питання щодо Баша.
Денніс

Відповіді:


267

Існує список символів, які розділяють лексеми в BASH. Ці символи називаються метасимволу і вони |, &, ;, (, ), <, >, простір і вкладки . З іншого боку, фігурні дужки ( {і }) - це просто звичайні символи, які складають слова.

Пропустіть другий пробіл раніше, ніж }буде зроблено, оскільки &це метахарактер. Тому ваша татуювання повинна мати хоча б один космічний символ.

:(){ :|:&};:

35
Просте рішення: перемістіть першу частину дао вліво і пересадіть шкіру між двома частинами.

23
Мені сподобався термін, on the other hand... каламбур призначений? ;): D (Вибачте, за коментар з теми.)
anishsane

4
Але це по-різному для zsh? Чим zsh відрізняється?
tfogo

2
Гарне пояснення, за винятком того, що {і }є оболонки ключові слова в даному контексті. Тільки якщо їх не визнають такими - через відсутність навколишніх просторів / метахарактерів - вони розглядаються як буквальна частина слова, до якої вони стають. (А потім є розширення
дужок

2
Дужки @DmitriChubarov дозволені в назвах команд (включаючи функції: {foo} () { echo hello; }"Ім'я", як визначено в bash"слові, що складається лише з буквено-цифрових символів і підкреслень, і починається з алфавітного символу або підкреслення", застосовується лише до імен змінних.
чепнер

82

Просто татуюйте а

#!/bin/zsh

shebang над ним, і ти будеш добре.


6
Якщо ми вибагливі, шебанг взагалі не працюватиме, оскільки оболонка, сподіваємось, zsh, перебуває в інтерактивному режимі, про що свідчить підказка ...
SzG

50

Фігурні дужки більше схожі на непарні ключові слова, ніж спеціальні символи, і їм потрібні пробіли. Наприклад, це відрізняється від дужок. Порівняйте:

(ls)

яка працює, і:

{ls}

яка шукає команду з ім'ям {ls}. Для роботи це повинно бути:

{ ls; }

Точка з комою зупиняє дужку закриття, яка приймається за параметр ls.

Все, що вам потрібно зробити, - це сказати людям, що ви використовуєте пропорційний шрифт із досить вузьким символом простору.


12
@DmitriChubarov - це дуже підлий трюк, використовуючи зовсім інше значення брекетів. Він розширює розділений комами список значень, який у даному випадку є просто ls.
Пітер Вестлейк

7
Але ... хлопче ... ти будеш мати татуювання до кінця свого життя! Ви позначали себе дурнем за весь час! І тоді ви навіть не змогли це виправити, перш ніж його зшити? Думаю, це два кроки від того, щоб бути дурним ;-) Без образи, товариш, мені просто цікаво.
Альфе

14
@Alfe Я спробував це до того, як я його татуював, але я спробував це в моєму zsh, я подумав, що він має такий самий аналіз, як і bash. Дурний мене, але я просто скажу людям, що це zsh. :)
шпидон

20
@spydon Або ви скажете їм, що ви спеціально випустили простір, щоб люди, що копіюють команду з вашої татуювання, випадково не запустили її і не зламали машину;)
ткніть

4
Гей, якщо він дійсний у zsh, чому б просто не додати #! / Bin / zsh прямо над ним (або перед ним)? Добре практично спочатку вказати оболонку.
Адам Міллер

41

Хоча це не легко видно шрифтом тату, насправді між дужкою та товстою кишкою є марка порядку в байті (BOM) (можливо, ви були в стані алкогольного сп’яніння, коли отримали татуювання, якого не помітили, але насправді це є) . Це залишає три очевидні можливості:

  1. Вам не вдалося ввести BOM під час транскрибування коду. Результат - очевидне застосування GIGO. Оболонка просто не розпізнає BOM, який відсутній у вашій невдалій транскрипції.
  2. Ваша оболонка занадто стара. Він не розпізнає символи Unicode, тому BOM (і, ймовірно, всі інші символи Unicode) ігнорується повністю, навіть якщо BOM в будь-якому місці, але початок файлу повинен трактуватися як нульова ширина, нерозривний простір .
  3. Ваша оболонка занадто нова. Використання BOM як ZWNBS застаріло, і автори реалізували майбутню версію Unicode, в якій це використання більше не дозволено.

40

а потім я додав пробіл, і він раптом спрацював ...

Це через те, як оболонка розбирається. Вам потрібно пробіл після початку визначення функції, тобто після {.

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

чинні. З іншої сторони,

foo() {echo hey&}

ні.


Насправді вам потрібен такий тату:

введіть тут опис зображення


З джерела :

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

Пропущення пробілу після {причин {echoінтерпретується як один маркер.


Еквівалентна форма

:(){ :|:& };:

було б

:(){
:|:& };:

Зауважте, що {в альтернативній версії пробілу немає місця , але розрив рядка змушує оболонку розпізнавати {як маркер.


"Пропущення пробілу після {викликає інтерпретацію {echo як один маркер." - так чи вважає аналізатор, що зіткнувся з командою, викликаною {echoдо того, як досяг потрібного вступного дужка?
Іона
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.