Espaços de nome separados para funções e variáveis ​​em shells POSIX

13

No traço, funções e variáveis ​​parecem viver em espaços para nome separados:

fn(){
    fn="hello world"
}
fn; echo "The value is $fn!" #prints: The value is hello world!
fn; echo "The value is $fn!" #prints: The value is hello world!
#the fn variable doesn't conflict with the fn function

Isso é um recurso específico do traço ou uma garantia POSIX?

PSkocik
fonte
2
Seu código não prova realmente que a fnfunção está em um espaço para nome separado; se executá-lo uma vez eliminasse sua definição, veríamos exatamente o mesmo comportamento. Você deve mostrar que a função ainda está definida, por exemplo, type fnposteriormente.
alexis

Respostas:

13

Uma garantia :

2.9.5 Comando de definição de função

Uma função é um nome definido pelo usuário que é usado como um comando simples para chamar um comando composto com novos parâmetros posicionais. Uma função é definida com um "comando de definição de função". [...]

A função é nomeada fname; o aplicativo deve garantir que seja um nome (consulte Nome XBD) e que não seja o nome de um utilitário interno especial. Uma implementação pode permitir outros caracteres no nome de uma função como uma extensão. A implementação deve manter espaços de nomes separados para funções e variáveis.

ilkkachu
fonte
Observe também que unsettem -ve -fpara escolher entre desmarcar a variável ou função pelo nome fornecido. bash(em oposição à maioria dos outros conchas) irá retirar a foo função com unset foose não há nenhuma foovariável (!), um comportamento permitido pelo POSIX. É por isso que, nos scripts POSIX, é uma boa prática sempre usar um -vou -f(e, é claro, também nos bashscripts, mas observe que unsetnem sempre é possível desmarcar uma variável bash, o bashescopo de variáveis ​​tem muitos problemas).
Stéphane Chazelas
Observe que no bash pré-shellshock, você teria problemas ao exportar a variável e a função com um nome determinado, pois o bash acabaria usando o mesmo nome de variável de ambiente para ambos (colocando-o duas vezes no ambiente, alguns comandos poderiam remover um deles)
Stéphane Chazelas 18/01/18
8

Variáveis ​​e funções residem em diferentes namespaces no dash e isso também é especificado pelo POSIX :

A implementação deve manter espaços de nomes separados para funções e variáveis.

Além disso, as variáveis ​​têm escopo global, por padrão. Alguns shells (por exemplo, bash, ksh e zsh) fornecem a localpalavra-chave para declarar variáveis ​​em uma função apenas com escopo local.

Portanto, sim, o comportamento que você está vendo é garantido pelo POSIX.

POSIX não padronizado local , ainda :

A descrição das funções em uma proposta inicial foi baseada na noção de que as funções deveriam se comportar como scripts de shell em miniatura; isto é, exceto no compartilhamento de variáveis , a maioria dos elementos de um ambiente de execução deve se comportar como se fosse um novo ambiente de execução, [..]

[..] Variáveis ​​locais dentro de uma função foram consideradas e incluídas em outra proposta anterior (controlada pelo built-in especial local), mas foram removidas porque não se encaixam no modelo simples desenvolvido para as funções e porque havia alguma oposição em adicionar ainda outro novo embutido especial que não fazia parte da prática histórica. As implementações devem reservar o identificador local(assim como typeseto KornShell), caso esse mecanismo de variável local seja adotado em uma versão futura deste padrão.

(ênfase minha)

maxschlepzig
fonte
O ash (do final dos anos 80), no qual o dash também tem local, uma das interfaces mais consistentes por aí (em comparação com a severamente quebrada no bash, por exemplo), bash apenas recentemente (4.4) pegou emprestado o local -(para escopo local para opções) do ash (implementando o escopo no estilo ash $-apenas para essa variável). O ksh e o yash não possuem local(apenas as variantes do pdksh local), mas typesetsim (no ksh93 typesetfornece escopo local (estático) apenas em funções declaradas usando a sintaxe ksh).
Stéphane Chazelas