Ambos estão errados com as configurações da opção zsh
default. Você pode ver facilmente o que está acontecendo usando echo
como o comando em vez de mv
.
Interativamente, parece que você tem a opção null_glob
definida. De acordo com a documentação zsh
, essa opção não é configurada por padrão. O que acontece com essa opção unset depende se outra opção, nomatch
, está definida ou não definida. Com nomatch
unset ( nonomatch
) você obteria isso:
% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% echo */*.{a,b} .
dir/file.a */*.b .
A expansão acontece em 2 etapas. Primeiro, */*.{a,b}
é expandido para 2 palavras: */*.a
e */*.b
. Então cada palavra é expandida como um padrão glob. O primeiro se expande para dir/file.a
e o segundo se expande para si mesmo porque não corresponde a nada. Tudo isso significa que, se você usar mv
e não echo
, mv
deverá tentar mover 2 arquivos: dir/file.a
(fino) e */*.b
(nenhum arquivo). Isso é o que acontece por padrão na maioria dos shells, como sh
e ksg
e bash
.
As configurações da opção zsh defaults são de que null_glob
não está definido e nomatch
está definido. Os scripts são executados com as configurações de opção padrão (a menos que você as altere em ~/.zshenv
ou /etc/zshenv
, o que você não deveria). Isso significa que, em scripts, você consegue isso:
% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% cat script.sh
#!/usr/bin/zsh
echo */*.{a,b} .
% ./script.sh
./script.sh:2: no matches found: */*.b
Como */*.b
não corresponde a nada, você recebe um erro devido a nomatch
.
Se você inserir setopt nonomatch
no script antes do comando echo
/ mv
, retornará ao comportamento incorreto como descrito acima: ele tenta mover um arquivo que não existe.
Se você inserir setopt null_glob
no script antes do comando echo
/ mv
, obterá o comportamento obtido em seu shell interativo, que é o que funciona.