Why is whitespace sometimes needed around metacharacters?

BashShellSyntaxSyntax Error

Bash Problem Overview


A few months ago I tattooed a fork bomb on my arm, and I skipped the whitespaces, because I think it looks nicer without them. But to my dismay, sometimes (not always) when I run it in a shell it doesn't start a fork bomb, but it just gives a syntax error.

bash: syntax error near unexpected token `{:'

Yesterday it happened when I tried to run it in a friend's Bash shell, and then I added the whitespace and it suddenly worked, :(){ :|:& };: instead of :(){:|:&};:

Does the whitespace matter; have I tattooed a syntax error on my arm?!

It seems to always work in zsh, but not in Bash.

A related question does not explain anything about the whitespaces, which really is my question; Why is the whitespace needed for Bash to be able to parse it correctly?

Bash Solutions


Solution 1 - Bash

There is a list of characters that separate tokens in BASH. These characters are called metacharacters and they are |, &, ;, (, ), <, >, space and tab. On the other hand, curly braces ({ and }) are just ordinary characters that make up words.

Omitting the second space before } will do, since & is a metacharacter. Therefore, your tattoo should have at least one space character.

:(){ :|:&};:

Solution 2 - Bash

Just tattoo a

#!/bin/zsh

shebang above it and you'll be fine.

Solution 3 - Bash

Braces are more like odd keywords than special symbols, and do need spaces. This is different to parentheses, for example. Compare:

(ls)

which works, and:

{ls}

which looks for a command named {ls}. To work, it has to be:

{ ls; }

The semicolon stops the closing brace being taken as a parameter to ls.

All you have to do is tell people that you are using a proportional-font with a rather narrow space character.

Solution 4 - Bash

Although not easily visible in the tatoo font, there's actually a Byte-Order Mark (BOM) between the brace and the colon (you may have been sufficiently intoxicated when you got the tatoo that you didn't notice it, but it's really there). This leaves three obvious possibilities:

  1. You've failed to type in the BOM when you transcribed the code. The result is an obvious application of GIGO. The shell simply doesn't recognize a BOM that isn't present in your failed transcription.
  2. Your shell is too old. It doesn't recognize Unicode characters, so the BOM (and probably all other Unicode characters) is being ignored completely, even though a BOM anywhere but the beginning of a file is supposed to be treated as a zero-width, non-breaking space.
  3. Your shell is too new. Use of a BOM as a ZWNBS is deprecated, and the authors have implemented a future version of Unicode in which this usage is no longer allowed.

Solution 5 - Bash

> and then I added the whitespace and it suddenly worked ...

It's because of how the shell parses. You need a space after the function definition begins, i.e. after the {.

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

are valid. On the other hand,

foo() {echo hey&}

isn't.


You actually need a tatoo like this:

enter image description here


From the source:

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

Omitting a space after the { causes the {echo to be interpreted as a single token.


An equivalent form of

:(){ :|:& };:

would be

:(){
:|:& };:

Note that there is no space after { in the alternate version, but a line-break causes the shell to recognize { as a token.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionspydonView Question on Stackoverflow
Solution 1 - BashDmitri ChubarovView Answer on Stackoverflow
Solution 2 - BashSzGView Answer on Stackoverflow
Solution 3 - BashPeter WestlakeView Answer on Stackoverflow
Solution 4 - BashJerry CoffinView Answer on Stackoverflow
Solution 5 - BashdevnullView Answer on Stackoverflow