Existe uma maneira de source
um script de shell em um espaço para nome, de preferência um script de shell bash, mas eu procuraria em outros shells se eles tivessem esse recurso e o bash não.
O que quero dizer com isso é, por exemplo, algo como "prefixar todos os símbolos definidos com algo para que eles não colidam com símbolos já definidos (nomes de variáveis, nomes de funções, aliases)" ou qualquer outro recurso que impeça colisões de nomes.
Se houver uma solução em que eu possa namespace no source
momento ( NodeJS
estilo), isso seria o melhor.
Código de exemplo:
$ echo 'hi(){ echo Hello, world; }' > english.sh
$ echo 'hi(){ echo Ahoj, světe; }' > czech.sh
$ . english.sh
$ hi
#=> Hello, world
$ . czech.sh #bash doesn't even warn me that `hi` is being overwritten here
$ hi
#=> Ahoj, světe
#Can't use the English hi now
#And sourcing the appropriate file before each invocation wouldn't be very efficient
( easiest thing ever )
. Mas não é exatamente isso que você procura. Eu acho que você poderia fazer( stuff in subshell; exec env ) | sed 's/^/namespace_/'
eeval
o resultado no shell pai, mas isso é meio desagradável.ksh93
. Os namespaces são fundamentais para ele - e todos os seus tipos de nomes (que também são tipificáveis) oferecem suporte ao namespacing. Também é muito mais rápido em praticamente todos os aspectos do quebash
, a propósito.env | sed ...
funcionaria para variáveis, eu poderia fazerset
para obter funções, mas a pesquisa e a substituição seriam um problema - as funções podem se chamar e você precisará substituir todas as invocações cruzadas por invocações cruzadas prefixadas, mas sem substituir o mesmas palavras em outras partes do código de definição de função, onde não é uma invocação. Para isso, você precisaria de um analisador de bash, não apenas de um regex, e ainda funcionaria apenas desde que as funções não se chamassem por eval.Respostas:
A partir
man ksh
de um sistema com umksh93
...E, para demonstrar, eis o conceito aplicado a um espaço de nome fornecido por padrão para todas as variáveis regulares do shell atribuídas em um
ksh93
shell. No exemplo a seguir, definirei umadiscipline
função que atuará como o.get
método atribuído à$PS1
variável shell. Cada variável shell basicamente obtém seu próprio espaço de nomes com, pelo menos, o padrãoget
,set
,append
, eunset
métodos. Após definir a função a seguir, sempre que a variável$PS1
for referenciada no shell, a saída dedate
será desenhada na parte superior da tela ...(Observe também a falta do
()
subshell na substituição de comando acima)Tecnicamente, os espaços para nome e as disciplinas não são exatamente a mesma coisa (porque as disciplinas podem ser definidas para aplicar global ou localmente a um espaço para nome específico ) , mas são parte integrante da conceitualização dos tipos de dados do shell, que são fundamentais para isso
ksh93
.Para abordar seus exemplos específicos:
...ou...
fonte
Eu escrevi uma função shell POSIX que pode ser usado para localmente namespace A builtin shell ou função em qualquer um
ksh93
,dash
,mksh
, oubash
(nomeado especificamente porque eu, pessoalmente, confirmou ao trabalho em todos estes) . Das conchas em que o testei, ele apenas falhou em atender às minhas expectativasyash
e nunca esperei que funcionassezsh
. Eu não testeiposh
. Desisti de qualquer esperança háposh
algum tempo e não o instalo há algum tempo. Talvez funcione emposh
...?Eu digo que é POSIX porque, pela minha leitura da especificação, tira proveito de um comportamento especificado de um utilitário básico, mas, reconhecidamente, a especificação é vaga a esse respeito e, pelo menos uma pessoa aparentemente discorda de mim. Geralmente, eu tive uma discordância com essa, e finalmente encontrei o erro como meu, e possivelmente também estou errado desta vez com a especificação, mas quando o questionei mais, ele não respondeu.
Como eu disse, no entanto, isso definitivamente funciona nas conchas acima mencionadas, e funciona, basicamente, da seguinte maneira:
O
command
comando é especificado como um utilitário basicamente disponível e um dos pré-$PATH
instalados. Uma de suas funções especificadas é agrupar utilitários embutidos especiais em seu próprio ambiente ao chamá-los, e assim ...... o comportamento das duas atribuições de linha de comando acima está correto por especificação. O comportamento de ambas as condições de erro também está correto e, de fato, é quase completamente duplicado na especificação. As atribuições prefixadas às linhas de comando de funções ou recursos especiais especiais são especificadas para afetar o ambiente atual do shell. Da mesma forma, os erros de redirecionamento são especificados como fatais quando apontados para qualquer um deles.
command
é especificado para suprimir o tratamento especial de recursos internos especiais nesses casos, e o caso de redirecionamento é realmente demonstrado por exemplo na especificação.Construções regulares, como
command
, por outro lado, são especificadas para serem executadas em um ambiente de subcamadas - o que não significa necessariamente o de outro processo , apenas que ele deve ser fundamentalmente indistinguível de um. Os resultados de chamar um built-in regular sempre devem se parecer com o que pode ser obtido de um$PATH
comando com capacidade semelhante . E entao...Mas o
command
comando não pode chamar funções de shell e, portanto, não pode ser usado para tornar seu tratamento especial discutível, como é possível para os componentes internos regulares. Isso também é especificado. De fato, a especificação diz que um utilitário primáriocommand
é que você pode usá-lo em uma função shell do invólucro chamada para outro comando para chamar esse outro comando sem auto-recursão, porque não chamará a função. Como isso:Se você não usasse
command
lá, acd
função quase definitivamente segfault para auto-recursão.Porém, como um embutido regular que pode chamar de embutidos especiais,
command
pode fazê-lo em um ambiente de subcamação . E assim, embora o estado atual do shell definido dentro possa se ater ao shell atual - certamenteread
o fez$var1
e o$var2
fez - pelo menos os resultados da linha de comando definem provavelmente não deveriam ...Agora, se
command
a capacidade de ser ou não um construtor regular e chamar diretamente de construtores especiais é apenas algum tipo de brecha inesperada no que diz respeito às definições da linha de comando, eu não sei, mas sei que pelo menos os quatro escudos já mencionado honra ocommand
espaço para nome.E embora
command
não possa chamar diretamente funções de shell, pode chamareval
como demonstrado, e pode fazê-lo indiretamente. Então, eu criei um wrapper de espaço para nome nesse conceito. É preciso uma lista de argumentos como:... exceto que a
command
palavra acima é reconhecida apenas como uma, se puder ser encontrada com um vazio$PATH
. Além localmente escopo variáveis do shell nomeadas na linha de comando, ele também localmente escopos todos variável com minúsculas nomes alfabéticos individuais e uma lista de outras padrão, como$PS3
,$PS4
,$OPTARG
,$OPTIND
,$IFS
,$PATH
,$PWD
,$OLDPWD
e alguns outros.E sim, por escopo localmente o
$PWD
e$OLDPWD
variáveis e depois explicitamentecd
ing para$OLDPWD
e$PWD
ele pode razoavelmente confiável âmbito do diretório de trabalho atual também. Isso não é garantido, embora tente bastante. Ele mantém um descritor para7<.
e quando seu destino de quebra retornacd -P /dev/fd/7/
. Se o diretório de trabalho atual estiverunlink()
temporário, ele ainda deve pelo menos conseguir voltar para ele, mas emitirá um erro feio nesse caso. E como ele mantém o descritor, também não acho que um kernel sadio permita que seu dispositivo raiz seja desmontado (???) .Ele também escopo localmente as opções de shell e as restaura no estado em que as encontrou quando o utilitário empacotado retorna. Trata
$OPTS
especialmente na medida em que mantém uma cópia em seu próprio escopo à qual atribui inicialmente o valor$-
. Depois de também manipular todas as atribuições na linha de comando, ele fará umset -$OPTS
pouco antes de chamar seu destino de quebra automática. Dessa forma, se você definir-$OPTS
na linha de comando, poderá definir as opções de shell do seu destino de quebra automática. Quando o destino retornar, ele iráset +$- -$OPTS
com sua própria cópia de$OPTS
(que não é afetada pela linha de comando define) e restaurará tudo para o estado original.Obviamente, não há nada que impeça o chamador de sair de alguma forma explicitamente
returrn
da função por meio do alvo de quebra ou de seus argumentos. Isso impedirá qualquer restauração / limpeza do estado que, de outra forma, seria tentada.Para fazer tudo o que é necessário, é preciso
eval
aprofundar três . Primeiro, ele se envolve em um escopo local, depois, de dentro, lê argumentos, valida-os para nomes de shell válidos e sai com erro se encontrar um que não é. Se todos os argumentos forem válidos e, eventualmente, uma causacommand -v "$1"
retornar true (lembre-se:$PATH
está vazio neste momento) ,eval
a linha de comando definirá e transmitirá todos os argumentos restantes para o destino de quebra de linha (embora ignore o caso especial dens
- porque isso não seja muito útil, e trêseval
segundos de profundidade é mais do que suficiente) .Basicamente, funciona assim:
Há alguns outros redirecionamentos e, e alguns testes estranhas a ver com a forma como algumas conchas colocar
c
em$-
e, em seguida, recusar-se a aceitá-la como uma opção paraset
(???) , mas todos os seus auxiliares, e principalmente usado apenas para salvar a partir emitindo saída indesejada e similar em casos extremos. E é assim que funciona. Ele pode fazer essas coisas porque configura seu próprio escopo local antes de chamar seu utilitário agrupado em um tal aninhado.É longo, porque eu tento ter muito cuidado aqui - três
evals
é difícil. Mas com isso você pode fazer:Indo um passo adiante e persistindo no namespace do escopo local do utilitário agrupado, não deve ser muito difícil. E mesmo como está escrito, ele já define uma
$LOCALS
variável para o utilitário agrupado, que é composta apenas por uma lista separada por espaço de todos os nomes que definiu no ambiente do utilitário agrupado.Gostar:
... o que é perfeitamente seguro -
$IFS
foi higienizado com seu valor padrão e somente nomes válidos de shell o fazem, a$LOCALS
menos que você o defina na linha de comando. E mesmo que possa haver caracteres glob em uma variável dividida, você também pode definirOPTS=f
na linha de comando o utilitário agrupado para proibir sua expansão. Em qualquer caso:E aqui está a função. Todos os comandos são prefixados com /
\
para evitaralias
expansões:fonte