Estou tendo dificuldade para definir e executar minhas próprias funções de shell no zsh. Segui as instruções na documentação oficial e tentei com um exemplo fácil primeiro, mas não consegui fazê-lo funcionar.
Eu tenho uma pasta:
~/.my_zsh_functions
Nesta pasta, tenho um arquivo chamado functions_1
com rwx
permissões de usuário. Neste arquivo, tenho a seguinte função de shell definida:
my_function () {
echo "Hello world";
}
Eu defini FPATH
para incluir o caminho para a pasta ~/.my_zsh_functions
:
export FPATH=~/.my_zsh_functions:$FPATH
Posso confirmar que a pasta .my_zsh_functions
está no caminho das funções com echo $FPATH
ouecho $fpath
No entanto, se eu tentar o seguinte no shell:
> autoload my_function
> my_function
Eu recebo:
zsh: my_test_function: arquivo de definição de função não encontrado
Preciso fazer mais alguma coisa para poder ligar my_function
?
Atualizar:
As respostas até agora sugerem o fornecimento do arquivo com as funções zsh. Isso faz sentido, mas estou um pouco confuso. O zsh não deveria saber onde estão esses arquivos FPATH
? Qual é o propósito de autoload
então?
fonte
Respostas:
No zsh, o caminho de busca da função ($ fpath) define um conjunto de diretórios, que contêm arquivos que podem ser marcados para serem carregados automaticamente quando a função que eles contêm é necessária pela primeira vez.
O Zsh possui dois modos de carregamento automático de arquivos: a maneira nativa do Zsh e outro modo que se assemelha ao carregamento automático do ksh. Este último estará ativo se a opção KSH_AUTOLOAD estiver configurada. O modo nativo do Zsh é o padrão e não discutirei o contrário aqui (consulte "man zshmisc" e "man zshoptions" para obter detalhes sobre o carregamento automático no estilo ksh).
OK. Digamos que você tenha um diretório `~ / .zfunc 'e deseje que ele faça parte do caminho de busca da função, faça o seguinte:
Isso adiciona seu diretório privado à frente do caminho de pesquisa. Isso é importante se você deseja substituir as funções da instalação do zsh por você mesmo (como quando você deseja usar uma função de conclusão atualizada como `_git 'do repositório CVS do zsh por uma versão mais antiga do shell).
Também é importante notar que os diretórios do `$ fpath 'não são pesquisados recursivamente. Se você deseja que seu diretório privado seja pesquisado recursivamente, será necessário cuidar disso, assim (o snippet a seguir requer que a opção `EXTENDED_GLOB 'seja configurada):
Pode parecer enigmático para quem não é treinado, mas na verdade apenas adiciona todos os diretórios abaixo de `~ / .zfunc 'a` $ fpath', enquanto ignora os diretórios chamados "CVS" (o que é útil, se você planeja fazer o checkout completo) árvore de funções do CVS do zsh para o seu caminho de pesquisa particular).
Vamos supor que você tenha um arquivo `~ / .zfunc / hello 'que contenha a seguinte linha:
Tudo o que você precisa fazer agora é marcar a função a ser carregada automaticamente na primeira referência:
"O que é o -Uz?", Você pergunta? Bem, isso é apenas um conjunto de opções que farão com que o 'carregamento automático' faça a coisa certa, independentemente de quais opções estejam sendo definidas de outra forma. O `U 'desativa a expansão do alias enquanto a função está sendo carregada e o` z' força o carregamento automático no estilo zsh, mesmo que o `KSH_AUTOLOAD 'esteja definido por qualquer motivo.
Depois disso, você poderá usar sua nova função `hello ':
Uma palavra sobre o fornecimento desses arquivos: Isso é errado . Se você tivesse originado esse arquivo `~ / .zfunc / hello ', ele imprimiria" Hello world ". uma vez. Nada mais. Nenhuma função será definida. Além disso, a idéia é carregar apenas o código da função quando necessário . Após a chamada `autoload ', a definição da função não é lida. A função está marcada apenas para ser carregada automaticamente mais tarde, conforme necessário.
E, finalmente, uma observação sobre $ FPATH e $ fpath: Zsh mantém esses parâmetros como parâmetros vinculados. O parâmetro em minúsculas é uma matriz. A versão em maiúsculas é uma cadeia de caracteres escalar, que contém as entradas da matriz vinculada unidas por dois pontos entre as entradas. Isso é feito porque o manuseio de uma lista de escalares é muito mais natural usando matrizes, além de manter a compatibilidade com versões anteriores do código que usa o parâmetro escalar. Se você optar por usar $ FPATH (o escalar), precisará ter cuidado:
funcionará, enquanto o seguinte não:
O motivo é que a expansão do til não é realizada entre aspas duplas. Esta é provavelmente a fonte dos seus problemas. Se
echo $FPATH
imprimir um til e não um caminho expandido, não funcionará. Para estar seguro, eu usaria $ HOME em vez de um til como este:Dito isto, prefiro usar o parâmetro array como fiz no topo desta explicação.
Você também não deve exportar o parâmetro $ FPATH. É necessário apenas pelo processo atual do shell e não por nenhum de seus filhos.
Atualizar
Em relação ao conteúdo dos arquivos em `$ fpath ':
Com o carregamento automático no estilo zsh, o conteúdo de um arquivo é o corpo da função que ele define. Assim, um arquivo chamado "hello" contendo uma linha
echo "Hello world."
define completamente uma função chamada "hello". Você é livre para colocarhello () { ... }
o código em prática , mas isso seria supérfluo.A alegação de que um arquivo pode conter apenas uma função não está totalmente correta.
Especialmente se você observar algumas funções do sistema de conclusão baseado em funções (compsys), rapidamente perceberá que isso é um equívoco. Você é livre para definir funções adicionais em um arquivo de função. Você também é livre para fazer qualquer tipo de inicialização, o que pode ser necessário na primeira vez que a função é chamada. No entanto, quando você definir, sempre definirá uma função chamada como o arquivo no arquivo e chamará essa função no final do arquivo, para que seja executada na primeira vez em que a função for referenciada.
Se - com subfunções - você não definiu uma função chamada como o arquivo no arquivo, você acabaria com essa função com definições de funções (a saber, as subfunções no arquivo). Você definiria efetivamente todas as suas subfunções toda vez que chamar a função denominada como o arquivo. Normalmente, não é isso que você deseja, então você redefiniria uma função, denominada como o arquivo dentro do arquivo.
Vou incluir um esqueleto curto, que lhe dará uma idéia de como isso funciona:
Se você executasse este exemplo bobo, a primeira execução seria assim:
E as chamadas consecutivas ficarão assim:
Eu espero que isso esclareça as coisas.
(Um dos exemplos mais complexos do mundo real que usa todos esses truques é a função ` _tmux ' já mencionada no sistema de conclusão baseado em funções do zsh.)
fonte
my_function () { }
no seuHello world
exemplo. Se a sintaxe não for necessária, quando seria útil usá-la?O nome do arquivo em um diretório nomeado por um
fpath
elemento deve corresponder ao nome da função de carregamento automático que ele define.Sua função é nomeada
my_function
e~/.my_zsh_functions
é o diretório pretendido no seufpath
, portanto a definição demy_function
deve estar no arquivo~/.my_zsh_functions/my_function
.O plural no nome do arquivo proposto (
functions_1
) indica que você estava planejando colocar várias funções no arquivo. Não é assim que ofpath
carregamento automático funciona. Você deve ter uma definição de função por arquivo.fonte
ceder
source ~/.my_zsh_functions/functions1
no terminal e avaliarmy_function
, agora você poderá chamar a funçãofonte
FPATH
eautoload
então? Por que eu também preciso originar o arquivo? Veja minha pergunta atualizada.Você pode "carregar" um arquivo com todas as suas funções no seu $ ZDOTDIR / .zshrc assim:
Ou pode usar um ponto "." em vez de "fonte".
fonte
FPATH
eautoload
então? Por que eu também preciso originar o arquivo? Veja minha pergunta atualizada.Definitivamente, a terceirização não é a abordagem correta, pois o que você deseja é ter funções inicializadas preguiçosamente. É para isso que
autoload
serve. Veja como você realiza o que procura.No seu
~/.my_zsh_functions
, você diz que deseja colocar uma função chamadamy_function
echos "olá mundo". Mas você o envolve em uma chamada de função, que não é como isso funciona. Em vez disso, você precisa criar um arquivo chamado~/.my_zsh_functions/my_function
. Nele, basta colocarecho "Hello world"
, não em um wrapper de função. Você também pode fazer algo assim se realmente preferir ter o invólucro.Em seguida, no seu
.zshrc
arquivo, adicione o seguinte:Ao carregar um novo shell ZSH, digite
which my_function
. Você deve ver isso:ZSH acabou de apagar minha_função para você
autoload -X
. Agora, corra,my_function
mas apenas digitemy_function
. Você deverá ver aHello world
impressão e agora, quando executar,which my_function
deverá ver a função preenchida assim:Agora, a verdadeira mágica vem quando você configura toda a
~/.my_zsh_functions
pasta para trabalharautoload
. Se você deseja que cada arquivo que você solte nesta pasta funcione dessa maneira, altere o que você coloca no seu.zshrc
para algo como isto:fonte