qual é o equivalente zsh da exportação -f do bash

24

Então eu comecei a usar zsh. Eu gosto disso tudo. Parece muito legal e liso, e o fato de o diretório de trabalho atual e a linha de comando real estarem em linhas diferentes é bom, mas ao mesmo tempo, percebo que isso zshpode ser um pouco mais lento do que bash, especialmente ao imprimir texto no tela.

O que mais gostei foi o fato de zshser "compatível com versões anteriores" de todas as funções que defini no meu .bashrc.

Uma queixa embora. Todas as funções funcionam perfeitamente, mas não consigo descobrir como o sistema de exportação funciona.

Eu tive algumas dessas .bashrcfunções exportadas para poder usá-las em outros lugares, como scripts e programas externos export -f.

No zsh, a exportação nem parece ser comentada. É carregamento automático? Essas duas coisas são iguais? Estou tendo muita dificuldade em descobrir isso.

ixtmixilix
fonte
2
Essa é uma pergunta muito antiga, mas quero dizer que "o diretório de trabalho atual e a linha de comando real estão em linhas diferentes" não tem nada a ver com o zsh. Depende de como você configura seu prompt, isso é tudo.
4ae1e1

Respostas:

11

Variáveis ​​de ambiente que contêm funções são um hack do bash. Zsh não tem nada parecido. Você pode fazer algo semelhante com algumas linhas de código. Variáveis ​​de ambiente contêm seqüências de caracteres; As versões mais antigas do bash, antes da descoberta do Shellshock , armazenavam o código da função em uma variável cujo nome é o da função e cujo valor é () {seguido pelo código da função seguido por }. Você pode usar o código a seguir para importar variáveis ​​com essa codificação e tentar executá-las com configurações do tipo bash. Observe que o zsh não pode emular todos os recursos do bash, tudo o que você pode fazer é se aproximar um pouco (por exemplo, para $foodividir o valor e expandir curingas e criar matrizes baseadas em 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Como observou Stéphane Chazelas , o descobridor original do Shellshock, uma versão anterior desta resposta poderia executar código arbitrário nesse momento se a definição da função estivesse malformada. Essa versão não funciona, mas é claro, assim que você executa qualquer comando, pode ser uma função importada do ambiente.)

As versões pós-Shellshock do bash codificam funções no ambiente usando nomes de variáveis ​​inválidos (por exemplo BASH_FUNC_myfunc%%). Isso dificulta a análise confiável, pois o zsh não fornece uma interface para extrair esses nomes de variáveis ​​do ambiente.

Eu não recomendo fazer isso. Confiar nas funções exportadas dos scripts é uma péssima idéia: cria uma dependência invisível no seu script. Se você executar seu script em um ambiente que não tem sua função (em outra máquina, em um trabalho cron, após alterar os arquivos de inicialização do shell, ...), seu script não funcionará mais. Em vez disso, armazene todas as suas funções em um ou mais arquivos separados (algo como ~/lib/shell/foo.sh) e inicie seus scripts importando as funções que ele usa ( . ~/lib/shell/foo.sh). Dessa forma, se você modificar foo.sh, poderá pesquisar facilmente quais scripts contam com ele. Se você copiar um script, poderá descobrir facilmente quais arquivos auxiliares ele precisa.

O Zsh (e o ksh antes dele) torna isso mais conveniente, fornecendo uma maneira de carregar automaticamente funções nos scripts em que são usadas. A restrição é que você pode colocar apenas uma função por arquivo. Declare a função como carregada automaticamente e coloque a definição da função em um arquivo cujo nome é o nome da função. Coloque esse arquivo em um diretório listado em $fpath(que você pode configurar através da FPATHvariável de ambiente). No seu script, declare funções carregadas automaticamente com autoload -U foo.

Além disso, o zsh pode compilar scripts, para economizar tempo de análise. Ligue zcompilepara compilar um script. Isso cria um arquivo com a .zwcextensão Se esse arquivo estiver presente, autoloadserá carregado o arquivo compilado em vez do código-fonte. Você pode usar a zrecompilefunção para (re) compilar todas as definições de função em um diretório.

Gilles 'SO- parar de ser mau'
fonte
1
Engraçado como o seu código tem a mesma vulnerabilidade de shellshock bash(não verifica se o conteúdo da variável é apenas uma definição de função e processa qualquer nome de variável como HTTP_HOSTou LC_X). Boa resposta caso contrário.
Stéphane Chazelas
@ StéphaneChazelas Se você deseja executar comandos com funções importadas do ambiente, está praticamente perdido. Mas atualizei o código de importação para não executar código arbitrário. Porém, não é muito útil, pois o bash pós-shellshock não codifica suas funções exportadas da mesma maneira.
Gilles 'SO- stop be evil'
Agora você corrigiu o equivalente a CVE-2014-6271, mas provavelmente ainda está exposto a muitas vulnerabilidades do tipo CVE-2014-6277 / 6278 ... pois ainda está expondo o analisador zsh ao código em qualquer variável incluindo alguns que estão potencialmente sob controle de invasores em alguns contextos (como o código zsh -c 'functions[f]=$VAR' é analisado, mesmo que a ffunção nunca seja chamada). A solução é considerar apenas variáveis ​​cujo nome segue um modelo reservado como esse $BASH_FUNC_x%%, mas, como você diz, zshnão possui API para listar ou recuperar esses. Você precisaria ligar, perlpor exemplo.
Stéphane Chazelas 4/17
7

Se você colocar sua declaração de função em .zshenv , sua função será utilizável a partir de um script sem nenhum esforço.

rools
fonte
Por que você recusou minha resposta? Por favor explique.
Rools
Ainda esperando por uma resposta e ainda trabalhando!
Rools
Acabei de descobrir esta resposta e é uma solução ideal.
AFH
Eu não diminuí o voto. E TBH, o OP estava perguntando sobre exportar coisas do .bashrc, o que é uma péssima idéia, é melhor colocá-las em um script para não acabar com um ambiente enorme. Mas sua solução é apenas uma variante da mesma má idéia, coloque todos os seus scripts .zshenve diminui a velocidade de toda chamada do zsh, analisando muito código que nunca é usado. Além disso, não é o mesmo que exportar uma função, assim como uma variável exportada, uma função exportada está disponível apenas para processos filhos. Considerando que o material que você coloca .zshenvestá disponível para todos os zsh.
Metamórfico
Finalmente, se você confiar no código pessoal que você colocou no seu .zshenv, todos os seus scripts serão totalmente não portáveis. Normalmente, os scripts podem depender um do outro, o que é bom, você os distribui juntos. Mas se eles dependem de ter funções especiais .zshenv, ninguém vai querer usá-las, ou eles teriam que ser chamados com um especial ZDOTDIR, impedindo que o seu próprio .zshenvseja executado. Seria uma dor.
Metamórfico