A razão simplificada é a existência de um caractere: space.
As expansões de chaves não processam espaços (sem aspas).
Uma {...}
lista precisa de espaços (sem aspas).
A resposta mais detalhada é como o shell analisa uma linha de comando .
O primeiro passo para analisar (entender) uma linha de comando é dividi-la em partes.
Essas partes (geralmente chamadas de palavras ou tokens) resultam da divisão de uma linha de comando em cada meta-caractere do link :
- Divide o comando em tokens separados pelo conjunto fixo de metacaracteres: ESPAÇO, TAB, NEWLINE,;, (()), <,>, | e &. Os tipos de tokens incluem palavras, palavras-chave, redirecionadores de E / S e ponto e vírgula.
Meta-caracteres: spacetabenter;,<>|e &.
Após a divisão, as palavras podem ser de um tipo (como entendido pelo shell):
- Pré-atribuições de comando:
LC=ALL ...
- Comando
LC=ALL echo
- Argumentos
LC=ALL echo "hello"
- Redirecionamento
LC=ALL echo "hello" >&2
Expansão de cinta
Somente se uma "cadeia de chaves" (sem espaços ou metacaracteres) for uma única palavra (como descrita acima) e não for citada , ela será candidata a "expansão de chaves". Mais verificações são realizadas na estrutura interna posteriormente.
Assim, isto: se {ls,-l}
qualifica como "expansão de chave" para se tornar ls -l
, como first word
ou argument
(no bash, zsh é diferente).
$ {ls,-l} ### executes `ls -l`
$ echo {ls,-l} ### prints `ls -l`
Mas isso não irá: {ls ,-l}
. O Bash irá dividir spacee analisar a linha como duas palavras: {ls
e ,-l}
que acionará a command not found
(o argumento ,-l}
está perdido):
$ {ls ,-l}
bash: {ls: command not found
Sua linha: {ls;echo hi}
não se tornará uma "expansão Brace" por causa dos dois meta-caracteres ;e space.
Ele será dividido em este três partes: {ls
novo comando: echo
hi}
. Entenda que o ;gatilho inicia o novo comando. O comando {ls
não será encontrado e o próximo comando será impresso hi}
:
$ {ls;echo hi}
bash: {ls: command not found
hi}
Se for colocado após algum outro comando, iniciará um novo comando após o ;:
$ echo {ls;echo hi}
{ls
hi}
Lista
Um dos "comandos compostos" é uma "Lista Brace" (minhas palavras): { list; }
.
Como você pode ver, é definido com espaços e um fechamento ;
.
Os espaços e ;são necessários porque ambos {
e }
são " Palavras Reservadas ".
E, portanto, para ser reconhecido como palavras, deve estar cercado por meta-caracteres (quase sempre space:).
Conforme descrito no ponto 2 da página vinculada
- Verifica o primeiro token de cada comando para ver se é ...., {, ou (, então o comando é realmente um comando composto.
Seu exemplo: {ls;echo hi}
não é uma lista.
Precisa de um fechamento ;e um espaço (pelo menos) depois {. O último }é definido pelo fechamento ;.
Esta é uma lista { ls;echo hi; }
. E isso { ls;echo hi;}
também é (menos usado, mas válido) (Obrigado @choroba pela ajuda).
$ { ls;echo hi; }
A-list-of-files
hi
Mas como argumento (o shell sabe a diferença) para um comando, ele dispara um erro:
$ echo { ls;echo hi; }
bash: syntax error near unexpected token `}'
Mas tenha cuidado com o que você acredita que o shell está analisando:
$ echo { ls;echo hi;
{ ls
hi
{
interpretado como uma lista de comandos, se aparecer no início de um comando e como uma expansão de chave, caso contrário, mas não tenho certeza.