Bash – Separator Between Command List and }

bash

The Bash Manual says

{ list; } 

Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is
created. The semicolon (or newline) following list is required.

The braces are reserved words, so they must be separated from the list
by blanks or other shell metacharacters.

The parentheses are operators, and are recognized as separate tokens
by the shell even if they are not separated from the list by
whitespace.

If I remove the semicolon, like this:

$ { date }
>
  1. Why does it expect stdin input?

  2. A metacharacter is a character that separates words.
    The semicolon and whitespace are both "shell metacharacters". Why can't whitespace separate words date and }? Why do we need a semicolon instead of a whitespace for separating the words?

Best Answer

  1. It's waiting for the closing }. You've entered a list with one command, date }, and a newline, so you're still inside the command group and can either add another command to the list or terminate it.

    So it's not waiting for standard input (exactly), it's waiting for you to complete the command you started on the first line. If you enter } here, you'll (probably) get an error from the date command saying that it doesn't understand "}".

  2. { and } are valid arguments to common commands, as seen in point 1. For example, find uses {} as an argument.

    Specifically, only exactly "{" and "}" are reserved words. Reserved words in the shell only matter when they're given exactly as an entire word of their own, and only where they're specifically expected. The most important place they're expected is at the start of a command.

    The semicolon or newline means that } appears at the start of the next command in the list, where it can be recognised as a reserved word and given its special treatment. This is specified by POSIX for the shell grammar:

    This rule also implies that reserved words are not recognized except in certain positions in the input, such as after a <newline> or <semicolon>; the grammar presumes that if the reserved word is intended, it is properly delimited by the user

    It would be annoying if "then", another reserved word, couldn't be used as a normal word, so that basically makes sense. ( and ), by contrast, are operators, can appear anywhere, and need to be escaped if they're used for their literal values. This is essentially a historical artefact, and given a do-over perhaps a more consistent choice would be made in one direction or another, or perhaps a more complex parser would be mandated.


For Bash in particular, braces for command grouping also need to be distinguished from braces for brace expansion, and the parser makes an assumption that you're unlikely to be brace-expanding a command that starts with a space.

There is a choice whether to maintain corner-case historical compatibility or not, and some other shells, such as zsh, have cleverer parsers and are able to deal with { date } with the meaning you intended.