web-dev-qa-db-ger.com

Warum wird bei Metazeichen manchmal ein Leerzeichen benötigt?

Vor ein paar Monaten habe ich eine Gabelbombe auf meinen Arm tätowiert und die Leerzeichen übersprungen, weil ich denke, dass es ohne sie schöner aussieht. Aber zu meiner Enttäuschung wird manchmal (nicht immer), wenn ich es in einer Shell starte, keine Gabelbombe gestartet, sondern lediglich eine Syntax angegeben Error.

bash: syntax error near unexpected token `{:'

Gestern passierte es, als ich versuchte, es in der Bash Shell eines Freundes auszuführen. Dann fügte ich das Leerzeichen hinzu und es funktionierte plötzlich :(){ :|:& };: anstelle von :(){:|:&};:

Ist das Leerzeichen wichtig? habe ich einen Syntaxfehler an meinem Arm tätowiert ?!

Es scheint immer in zsh zu funktionieren, aber nicht in Bash.

Eine verwandte Frage erklärt nichts über die Leerzeichen, was wirklich meine Frage ist; Warum wird das Leerzeichen benötigt, damit Bash es korrekt analysieren kann?

538
spydon

Es gibt eine Liste von Zeichen, die Token in BASH trennen. Diese Zeichen heißen Metazeichen und sind |, &, ;, (, ), <, >, Leerzeichen und Tabulator. Auf der anderen Seite sind geschweifte Klammern ({ und }) nur gewöhnliche Zeichen, aus denen Wörter bestehen.

Das Weglassen des zweiten Leerzeichens vor } ist ausreichend, da & ein Metazeichen ist. Daher sollte Ihr Tattoo mindestens ein Leerzeichen haben.

:(){ :|:&};:
266
Dmitri Chubarov

Einfach tätowieren a

#!/bin/zsh

Shebang darüber und es wird dir gut gehen.

80
SzG

Klammern ähneln eher ungeraden Stichwörtern als speziellen Symbolen und benötigen Leerzeichen. Dies unterscheidet sich beispielsweise von Klammern. Vergleichen Sie:

(ls)

was funktioniert und:

{ls}

das nach einem Befehl namens {ls} sucht. Um zu arbeiten, muss es sein:

{ ls; }

Das Semikolon verhindert, dass die schließende Klammer als Parameter für ls verwendet wird.

Alles, was Sie tun müssen, ist den Leuten mitzuteilen, dass Sie eine Proportionalschrift mit einem ziemlich engen Leerzeichen verwenden.

50
Peter Westlake

Obwohl in der Tätowierungsschriftart nicht leicht sichtbar, befindet sich zwischen der geschweiften Klammer und dem Doppelpunkt tatsächlich ein Byte-Order Mark (BOM). . Dies lässt drei offensichtliche Möglichkeiten:

  1. Sie haben die Stückliste nicht eingegeben, als Sie den Code transkribiert haben. Das Ergebnis ist eine offensichtliche Anwendung von GIGO. Die Shell erkennt einfach keine Stückliste, die in Ihrer fehlgeschlagenen Transkription nicht vorhanden ist.
  2. Deine Shell ist zu alt. Da Unicode-Zeichen nicht erkannt werden, wird die Stückliste (und wahrscheinlich auch alle anderen Unicode-Zeichen) vollständig ignoriert, obwohl eine Stückliste an einer anderen Stelle als am Anfang einer Datei als ein nicht unterbrechendes Leerzeichen mit der Breite Null behandelt werden soll .
  3. Deine Shell ist zu neu. Die Verwendung einer Stückliste als ZWNBS ist veraltet, und die Autoren haben eine zukünftige Unicode-Version implementiert, in der diese Verwendung nicht mehr zulässig ist.
40
Jerry Coffin

und dann habe ich das Leerzeichen hinzugefügt und es hat plötzlich funktioniert ...

Es liegt daran, wie die Shell analysiert. Sie benötigen ein Leerzeichen nach Beginn der Funktionsdefinition, d. H. Nach dem {.

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

sind gültig. Auf der anderen Seite,

foo() {echo hey&}

ist nicht.


Du brauchst tatsächlich eine Tätowierung wie diese:

enter image description here


Aus dem Quelle :

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

Das Weglassen eines Leerzeichens nach dem { bewirkt, dass der {echo als einzelnes Token interpretiert wird.


Eine äquivalente Form von

:(){ :|:& };:

wäre

:(){
:|:& };:

Beachten Sie, dass in der alternativen Version nach { kein Leerzeichen steht, aber ein Zeilenumbruch bewirkt, dass die Shell { als Token erkennt.

40
devnull