Descobri que definir a extglob
opção shell apenas dentro de um composto composto resulta em falha de globs estendidos subsequentes. As opções do shell precisam ser definidas fora dos comandos compostos? Não vi uma indicação de tal requisito nas páginas de manual do Bash.
Como exemplo, o script a seguir funciona bem (imprime a.0 a.1
):
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
shopt -s extglob
ls "a."!(b*)
No entanto, se as duas últimas linhas forem executadas como um comando composto, o script falhará com o seguinte erro:
syntax error near unexpected token `('
` ls "a."!(b*)'
Isso foi testado usando as versões Bash de 4.2 a 4.4 e com uma variedade de comandos compostos :
(1) condicional --if
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
if true; then
shopt -s extglob
ls "a."!(b*)
fi
(2) chaves --{ }
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
{
shopt -s extglob
ls "a."!(b*)
}
(3) subcamada -- ( )
:
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
(
shopt -s extglob
ls "a."!(b*)
)
Em todos os casos, se shopt
for movido para fora do comando composto, o script será bem-sucedido.
Nenhuma parte de um comando composto é executada antes de todo o comando ser analisado, o que está obliquamente documentado na seção Operação do Shell do manual: toda a tokenização e análise ocorrem antes que "o" comando seja executado. A ativação
extglob
altera a sintaxe do idioma adicionando novos operadores de correspondência de padrões, que são reconhecidos durante a tokenização.Como o
shopt
comando não foi executado no momento em que!(
é alcançado, ele é visto como uma tentativa de expansão do histórico (!
) ou o operador de controle(
, em vez de!(
ser visto como um único item (e o mesmo para@(
, etc, exceto que não há expansão do histórico lá).Quando a análise atinge esse token, qualquer um dos casos geralmente será um erro, embora
!(...)
no início de uma linha ou depois haja umtime
pipeline de subshell negado. "unexpected token `('
" significa que não foi possível aceitar uma expressão de subshell nesse local.Isso é um pouco irritante quando você deseja que o extglob seja ativado apenas temporariamente em um subshell. Uma solução alternativa é definir uma função que use o glob que você deseja, depois desabilite o extglob e chame a função do subshell com o extglob habilitado:
É muito chato.
O mesmo efeito acontece se você criar um alias dentro de um comando composto, porque eles também são processados antes da análise:
imprimirá
foo: command not found
, e depoisxyz
, porque o alias é criado, mas não estará disponível até queif
seja concluído.