22

I know the difference in purpose between parentheses () and curly braces {} when grouping commands in bash.

But why does the curly brace construct require a semicolon after the last command, whereas for the parentheses construct, the semicolon is optional?

$ while false; do ( echo "Hello"; echo "Goodbye"; ); done
$ while false; do ( echo "Hello"; echo "Goodbye" ); done
$ while false; do { echo "Hello"; echo "Goodbye"; }; done
$ while false; do { echo "Hello"; echo "Goodbye" }; done
bash: syntax error near unexpected token `done'
$ 

I'm looking for some insight as to why this is the case. I'm not looking for answers such as "because the documentation says so" or "because it was designed that way". I'd like to know why it was designed this is way. Or maybe if it is just a historical artifact?

This may be observed in at least the following versions of :

  • GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu)
  • GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
  • GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
Digital Trauma
  • 13,834
  • 2
  • 40
  • 73
  • 1
    For reference sake it may be helpful to note the version of bash used while testing. – Jonathon Reinhart Jan 20 '14 at 23:55
  • @JonathonReinhart - versions have been noted in the question - thanks. – Digital Trauma Jan 21 '14 at 00:04
  • 1
    How about "because that's [how it's documented](http://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping)". The subtle distinction between braces and parentheses is described clearly. – glenn jackman Jan 21 '14 at 01:07
  • While this has a good answer and isn't worth closing at this point, see [What is the rationale for closing "why" questions on language design?](https://meta.stackexchange.com/questions/170394/what-is-the-rationale-for-closing-why-questions-on-a-language-design) -- note that SO's scope is restricted to *practical*, answerable questions. If a question is historical in nature, it doesn't change how you engage in the practice of development. – Charles Duffy Jul 16 '18 at 23:13

1 Answers1

31

Because { and } are only recognized as special syntax if they are the first word in a command.


There are two important points here, both of which are found in the definitions section of the bash manual. First, is the list of metacharacters:

metacharacter

A character that, when unquoted, separates words. A metacharacter is a blank or one of the following characters: ‘|’, ‘&’, ‘;’, ‘(’, ‘)’, ‘<’, or ‘>’.

That list includes parentheses but not braces (neither curly nor square). Note that it is not a complete list of characters with special meaning to the shell, but it is a complete list of characters which separate tokens. So { and } do not separate tokens, and will only be considered tokens themselves if they are adjacent to a metacharacter, such as a space or a semi-colon.

Although braces are not metacharacters, they are treated specially by the shell in parameter expansion (eg. ${foo}) and brace expansion (eg. foo.{c,h}). Other than that, they are just normal characters. There is no problem with naming a file {ab}, for example, or }{, since those words do not conform to the syntax of either parameter expansion (which requires a $ before the {) or brace expansion (which requires at least one comma between { and }). For that matter, you could use { or } as a filename without ever having to quote the symbols. Similarly, you can call a file if, done or time without having to think about quoting the name.

These latter tokens are "reserved words":

reserved word

A word that has a special meaning to the shell. Most reserved words introduce shell flow control constructs, such as for and while.

The bash manual doesn't contain a complete list of reserved words, which is unfortunate, but they certainly include the Posix-designated:

!    {    }
case do   done elif else
esac fi   for  if   in
then until while

as well as the extensions implemented by bash (and some other shells):

[[   ]]
function  select time

These words are not the same as built-ins (such as [), because they are actually part of the shell syntax. The built-ins could be implemented as functions or shell scripts, but reserved words cannot because they change the way that the shell parses the command line.

There is one very important feature of reserved words, which is not actually highlighted in the bash manual but is made very explicit in Posix (from which the above lists of reserved words were taken, except for time):

This recognition [as a reserved word] shall only occur when none of the characters is quoted and when the word is used as:

  • The first word of a command …

(The full list of places where reserved words is recognized is slightly longer, but the above is a pretty good summary.) In other words, reserved words are only reserved when they are the first word of a command. And, since { and } are reserved words, they are only special syntax if they are the first word in a command.

Example:

ls }  # } is not a reserved word. It is an argument to `ls`
ls;}  # } is a reserved word; `ls` has no arguments

There is lots more I could write about shell parsing, and bash parsing in particular, but it would rapidly get tedious. (For example, the rule about when # starts a comment and when it is just an ordinary character.) The approximate summary is: "don't try this at home"; really, the only thing which can parse shell commands is a shell. And don't try to make sense of it: it's just a random collection of arbitrary choices and historical anomalies, many but not all based on the need to not break ancient shell scripts with new features.

Community
  • 1
  • 1
rici
  • 201,785
  • 23
  • 193
  • 283
  • 1
    They're clearly special as the OP has discovered, maybe you could expand on why they are special, and what is significant about *"if they are the first word in a command"*? – Kev Jan 21 '14 at 00:00
  • @Kev, as always, because the designers decided so. In fact, it allows you to write `echo {}` and get `{}` printed. – Ingo Jan 21 '14 at 00:06
  • @rici +1 for precision and concision. – John1024 Jan 21 '14 at 01:19
  • 1
    It's worth noting that `{` and `}` are defined as reserved words, not control operators like `(` and `)`. – chepner Jan 21 '14 at 04:04
  • @rici - I see John1024 likes the concision of this answer, but I'm afraid I'm a slower learner and need it spelled out in more detail, perhaps with examples, if that helps – Digital Trauma Jan 29 '14 at 01:12
  • 1
    @DigitalTrauma: There you go. A huge number of words to get back to the same place, including one very token example and a number of links to further information. After you read it all, let me know if it does anything to improve on the original concise answer. – rici Jan 29 '14 at 02:53
  • @rici - That is a fantastic answer! You really helped my understanding. Thankyou for indulging me! – Digital Trauma Jan 29 '14 at 03:25