Dlaczego białe znaki są czasami potrzebne wokół metaznaków?

543

Kilka miesięcy temu wytatuowałem bombę widelcową na ramieniu i pominąłem białe spacje, ponieważ uważam, że bez nich ładniej wygląda. Ale ku mojemu przerażeniu, czasami (nie zawsze), kiedy uruchamiam go w powłoce, nie uruchamia bomby widelcowej, ale po prostu daje błąd składniowy.

bash: syntax error near unexpected token `{:'

Wczoraj stało się, gdy próbowałem uruchomić go w powłoce Bash znajomego , a następnie dodałem spację i nagle zadziałało, :(){ :|:& };:zamiast:(){:|:&};:

Czy białe znaki mają znaczenie; wytatuowałem błąd składniowy na moim ramieniu ?!

Wydaje się, że zawsze działa w Zsh , ale nie w Bash.

Powiązane pytanie nic nie wyjaśnia białych spacji, co tak naprawdę jest moim pytaniem; Dlaczego spacja jest potrzebna, aby Bash mógł poprawnie parsować?

spydon
źródło
6
Zadałem to samo pytanie tutaj (z wyłączeniem części tatuażu).
Benoit
3
Ponadto dwukropka (:) nie można użyć jako nazwy funkcji (patrz: pubs.opengroup.org/onlinepubs/9699919799/utilities/… ) ... FreeBSD's / bin / sh nawet daje błąd w tym ...
Martin Tournoij
5
@Carpetsmoker: Nie jestem pewien, jak to jest istotne. To pytanie dotyczy Basha.
Dennis

Odpowiedzi:

267

Istnieje lista znaków oddzielających tokeny w BASH. Znaki te są nazywane metaznaki i są |, &, ;, (, ), <, >, przestrzeń i tab . Z drugiej strony, nawiasy klamrowe ( {i }) są zwykłymi znakami, które składają się na słowa.

Pominie to drugie miejsce wcześniej }, ponieważ &jest to metaznak. Dlatego twój tatuaż powinien mieć co najmniej jedną spację.

:(){ :|:&};:
Dmitrij Chubarow
źródło
35
Proste rozwiązanie: przesuń pierwszą część taoo w lewo i przeszczep skórę między dwiema częściami.
23
Podobał mi się termin on the other hand... gra słów zamierzona? ;): D (Przepraszam, że nie skomentowałem tematu.)
anishsane
4
Ale to inaczej w przypadku Zsh? Czym różni się Zsh?
tfogo,
2
Dobre wyjaśnienie, z wyjątkiem tego {i }słowami kluczowymi powłoki w tym kontekście. Tylko jeśli nie zostaną rozpoznane jako takie - z powodu braku otaczających spacji / metaznaków - są traktowane jako dosłowna część słowa, którego stają się częścią. (A potem jest nawias klamrowy, co dzieje się w innym kontekście.)
mklement0
2
@DmitriChubarov Nawiasy klamrowe są dozwolone w nazwach poleceń (łącznie z funkcjami:. {foo} () { echo hello; }„Nazwa”, zdefiniowana w bashjako „słowo składające się wyłącznie ze znaków alfanumerycznych i znaków podkreślenia i rozpoczynające się od znaku alfabetu lub znaku podkreślenia”, dotyczy tylko nazw zmiennych.
chepner
82

Po prostu wytatuuj a

#!/bin/zsh

wyskoczyć nad nią, a wszystko będzie dobrze.

SzG
źródło
6
Jeśli jesteśmy wybredni, shebang w ogóle nie działałby, ponieważ powłoka, miejmy nadzieję, zsh, jest w trybie interaktywnym, o czym świadczy monit ...
SzG
50

Nawiasy klamrowe są bardziej jak nieparzyste słowa kluczowe niż specjalne symbole i wymagają spacji. Na przykład różni się to od nawiasów. Porównać:

(ls)

który działa i:

{ls}

która szuka polecenia o nazwie {ls}. Aby działać, musi to być:

{ ls; }

Średnik zatrzymuje przyjmowanie nawiasu zamykającego jako parametru do ls.

Wszystko, co musisz zrobić, to powiedzieć ludziom, że używasz czcionki proporcjonalnej o raczej wąskim znaku spacji.

Peter Westlake
źródło
12
@DmitriChubarov - to bardzo podstępna sztuczka, wykorzystująca zupełnie inne znaczenie nawiasów klamrowych. Rozszerza rozdzieloną przecinkami listę wartości, która w tym przypadku jest tylko ls.
Peter Westlake
7
Ale… chłopcze… będziesz miał tatuaż do końca życia! Na zawsze oznaczyłeś siebie jako kujona! A potem nie udało ci się tego zrobić przed zszywaniem? To chyba dwa kroki od nerdy ;-) Bez obrazy, kolego, po prostu się zastanawiam.
Alfe,
14
@Afefe Próbowałem go, zanim wytatuowałem, ale spróbowałem w moim Zsh, myślałem, że ma to samo parsowanie jak bash. Głupiec ze mnie, ale powiem ludziom, że to zsh. :)
spydon
20
@spydon Albo mówisz im, że celowo opuściłeś przestrzeń, aby ludzie kopiujący polecenie z twojego tatuażu nie uruchomili go przypadkowo i nie rozbili maszyny;)
poke
4
Hej, jeśli jest poprawny w Zsh, dlaczego po prostu nie dodać #! / Bin / zsh tuż nad nim (lub przed nim)? W każdym razie dobrą praktyką jest określenie powłoki jako pierwszej.
Adam Miller
41

Chociaż nie jest łatwo widoczny w czcionce tatoo, między klamrą a okrężnicą znajduje się w rzeczywistości znak kolejności bajtów (BOM) (być może byłeś wystarczająco odurzony, kiedy dostałeś tatuaż, że go nie zauważyłeś, ale tak naprawdę jest) . Pozostawia to trzy oczywiste możliwości:

  1. Nie udało się wpisać BOM podczas transkrypcji kodu. Rezultatem jest oczywiste zastosowanie GIGO. Powłoka po prostu nie rozpoznaje BOM, który nie jest obecny w nieudanej transkrypcji.
  2. Twoja skorupa jest za stara. Nie rozpoznaje znaków Unicode, więc BOM (i prawdopodobnie wszystkie inne znaki Unicode) jest całkowicie ignorowany, nawet jeśli BOM gdziekolwiek poza początkiem pliku ma być traktowany jako niezniszczalna spacja o zerowej szerokości .
  3. Twoja skorupa jest zbyt nowa. Używanie BOM jako ZWNBS jest przestarzałe, a autorzy zaimplementowali przyszłą wersję Unicode, w której takie użycie nie jest już dozwolone.
Jerry Coffin
źródło
40

a potem dodałem biały znak i nagle zadziałało ...

Wynika to z tego, jak analizuje powłoka. Potrzebujesz spacji po rozpoczęciu definicji funkcji, tj. Po {.

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

są ważne. Z drugiej strony,

foo() {echo hey&}

nie jest.


Tak naprawdę potrzebujesz takiego tatuażu:

wprowadź opis zdjęcia tutaj


Ze źródła :

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

Pominięcie spacji {powoduje, że {echointerpretowany jest jako pojedynczy token.


Równoważna forma

:(){ :|:& };:

byłoby

:(){
:|:& };:

Zauważ, że {w alternatywnej wersji nie ma spacji , ale podział linii powoduje, że powłoka rozpoznaje {token.

diabelnie
źródło
„Pominięcie spacji po {powoduje, że {echo jest interpretowane jako pojedynczy token." - więc parser uważa, że ​​napotkał polecenie wywołane, {echozanim osiągnął wymagany nawias otwierający?
Jonasz