Como evitar colisões de namespace / poluição em um script destinado a ser originado?

3

Eu quero implementar um script foo.sh que culmina com a execução de um comando bar (com alguns argumentos). O comando bar modifica o ambiente atual do shell, o que significa que foo.sh deve ser originado 1 . (BTW, a implementação de bar está totalmente fora do meu controle.)

O propósito da maior parte do código em foo.sh é calcular os argumentos que serão passados para bar .

Para manter foo.sh razoavelmente legível / sustentável, acho que devo definir muitas variáveis auxiliares. Infelizmente, isso prepara o cenário para

  1. colisões de espaço de nomes (ou seja, anulando parâmetros existentes)
  2. poluição de namespace (ou seja, bagunçando o ambiente com parâmetros supérfluos)

Uma maneira possível de evitar, ou pelo menos atenuar, esses problemas é colocar a maioria do código foo.sh em uma função (com todas as suas variáveis declaradas como local ) que ecoa uma sequência de código adequada a ser eval 'ed dentro do escopo de chamada; por exemplo,

{
  __messy_calculation () {

      local x y z ...
      local bar_arg_1 bar_arg_2 ...
      ...
      echo "bar $bar_arg_1 bar_arg_2 ..."

  }

  eval "$( __messy_calculation )"

} always {

  unfunction __messy_calculation

}

Isso cuida do problema de poluição de namespace e reduz o problema de colisão de namespace para o nome da função. (Eu não sou um grande fã de usar o eval, no entanto.)

Eu acho que essa situação é genérica o suficiente para que já existam formas padronizadas de abordá-la. Se sim, por favor me avise.

1 Caso meu raciocínio seja falho, deixe-me apenas acrescentar que se eu colocar todo o código, incluindo a chamada para bar , em uma função, quando eu executar este Na linha de comando, o ambiente atual não é afetado, o que torna a função inútil. Por outro lado, se eu usar a linha que executa a chamada para bar , o ambiente atual é modificado como esperado.

    
por kjo 11.11.2015 / 23:53

1 resposta

0

Para variáveis, é possível usar uma função anônima (como observado no comentário acima). Isso significa que você pode definir quantas variáveis desejar. Os que você deseja ocultar do chamador que você prefixar com local , aqueles que você deseja comunicar ao chamador que você acabou de definir normalmente:

function {
  local my_var=foo
  your_var=bar
  : ...
}

Mas para funções que não funcionam, elas não podem ser declaradas local . Eu tive esse problema no meu zshrc e decidi prefixar todos os nomes de minhas funções "locais" com uma string curta (como você faz namespaces em C) e para fazer um curinga unfunction no final:

function foo-do-something () {
  : ...
}
function foo-do-some-more-stuff () {
  : ...
}
function foo-main () {
  local my_var=oof
  you_var=rab
  foo-do-something for bar
  foo-do-some-more-stuff with baz
}
foo-main
unfunction -m 'foo-*'

Esta não é uma solução ideal na minha opinião (prefiro funções locais), mas funciona para mim.

    
por 20.01.2017 / 10:58