I've noticed that { can be used in brace expansion:echo {1..8}or in command grouping:{ls;echo hi}How does bash know the difference?
How does bash differentiate between brace expansion and command grouping?
bash;shell script
A simplified reason is the existence of one character: space.Brace expansions do not process (un-quoted) spaces.A {...} list needs (un-quoted) spaces.The more detailed answer is how the shell parses a command line.The first step to parse (understand) a command line is to divide it into parts.These parts (usually called words or tokens) result from dividing a command line at each meta-character from the link:Splits the command into tokens that are separated by the fixed set of meta-characters: SPACE, TAB, NEWLINE, ;, (, ), <, >, |, and &. Types of tokens include words, keywords, I/O redirectors, and semicolons.Meta-characters: spacetabenter;,<>| and &.After splitting, words may be of a type (as understood by the shell): Command pre-asignements: LC=ALL ... Command                 LC=ALL echo Arguments                 LC=ALL echo hello Redirection                 LC=ALL echo hello >&2 Brace expansionOnly if a brace string (without spaces or meta-characters) is a single word (as described above) and is not quoted, it is a candidate for Brace expansion. More checks are performed on the internal structure later.Thus, this: {ls,-l} qualifies as Brace expansion to become ls -l, either as first word or argument (in bash, zsh is different).$ {ls,-l}            ### executes `ls -l`$ echo {ls,-l}       ### prints `ls -l`But this will not: {ls ,-l}. Bash will split on space and parse the line as two words: {ls and ,-l} which will trigger a command not found (the argument ,-l} is lost): $ {ls ,-l} bash: {ls: command not foundYour line: {ls;echo hi} will not become a Brace expansion because of the two meta-characters ; and space.It will be broken into this three parts: {ls new command: echo hi}. Understand that the ; triggers the start of a new command. The command {ls will not be found, and the next command will print hi}:$ {ls;echo hi}bash: {ls: command not foundhi}If it is placed after some other command, it will anyway start a new command after the ;:$ echo {ls;echo hi}{lshi}ListOne of the compound commands is a Brace List (my words): { list; }.As you can see, it is defined with spaces and a closing ;.The spaces and ; are needed because both { and } are Reserved Words.  And therefore, to be recognized as words, must be surrounded by meta-characters (almost always: space).As described in the point 2 of the linked pageChecks the first token of each command to see if it is .... , {, or (, then the command is actually a compound command.Your example: {ls;echo hi} is not a list.It needs a closing ; and one space (at least) after {. The last } is defined by the closing ;.This is a list { ls;echo hi; }. And this { ls;echo hi;} is also (less commonly used, but valid)(Thanks @choroba for the help).$ { ls;echo hi; }A-list-of-fileshiBut as argument (the shell knows the difference) to a command, it triggers an error:$ echo { ls;echo hi; }bash: syntax error near unexpected token `}'But be careful in what you believe the shell is parsing:$ echo { ls;echo hi;{ lshi