Me está costando definir y ejecutar mis propias funciones de shell en zsh. Seguí las instrucciones en la documentación oficial e intenté con un ejemplo sencillo primero, pero no pude hacerlo funcionar.
Tengo una carpeta:
~/.my_zsh_functions
En esta carpeta tengo un archivo llamado functions_1
con rwx
permisos de usuario. En este archivo tengo definida la siguiente función de shell:
my_function () {
echo "Hello world";
}
Definí FPATH
incluir la ruta a la carpeta ~/.my_zsh_functions
:
export FPATH=~/.my_zsh_functions:$FPATH
Puedo confirmar que la carpeta .my_zsh_functions
está en la ruta de funciones con echo $FPATH
oecho $fpath
Sin embargo, si luego intento lo siguiente desde el shell:
> autoload my_function
> my_function
Yo obtengo:
zsh: my_test_function: archivo de definición de función no encontrado
¿Hay algo más que deba hacer para poder llamar my_function
?
Actualizar:
Las respuestas hasta ahora sugieren obtener el archivo con las funciones zsh. Esto tiene sentido, pero estoy un poco confundido. ¿No debería saber zsh dónde están esos archivos FPATH
? ¿Cuál es el propósito de autoload
entonces?
fuente
Respuestas:
En zsh, la ruta de búsqueda de funciones ($ fpath) define un conjunto de directorios que contienen archivos que se pueden marcar para cargarse automáticamente cuando se necesita por primera vez la función que contienen.
Zsh tiene dos modos de carga automática de archivos: la forma nativa de Zsh y otro modo que se asemeja a la carga automática de ksh. Este último está activo si se establece la opción KSH_AUTOLOAD. El modo nativo de Zsh es el predeterminado y no hablaré de la otra manera aquí (consulte "man zshmisc" y "man zshoptions" para obtener detalles sobre la carga automática de estilo ksh).
Bueno. Supongamos que tiene un directorio `~ / .zfunc 'y desea que forme parte de la ruta de búsqueda de funciones, haga esto:
Eso agrega su directorio privado al frente de la ruta de búsqueda. Eso es importante si desea anular las funciones de la instalación de zsh con las suyas propias (por ejemplo, cuando desea utilizar una función de finalización actualizada como `_git 'del repositorio CVS de zsh con una versión instalada más antigua del shell).
También vale la pena señalar que los directorios de `$ fpath 'no se buscan de forma recursiva. Si desea que su directorio privado se busque de forma recursiva, tendrá que ocuparse de eso usted mismo, de esta manera (el siguiente fragmento requiere que se configure la opción `EXTENDED_GLOB '):
Puede parecer críptico para el ojo inexperto, pero realmente solo agrega todos los directorios debajo de '~ / .zfunc' a '$ fpath', mientras ignora los directorios llamados "CVS" (lo cual es útil, si está planeando pagar un todo árbol de funciones del CVS de zsh en su ruta de búsqueda privada).
Supongamos que tiene un archivo `~ / .zfunc / hello 'que contiene la siguiente línea:
Todo lo que necesita hacer ahora es marcar la función que se cargará automáticamente en su primera referencia:
"¿De qué se trata el -Uz?" Bueno, eso es solo un conjunto de opciones que harán que la 'carga automática' haga lo correcto, sin importar qué opciones se establezcan de lo contrario. La 'U' deshabilita la expansión de alias mientras se carga la función y la 'z' fuerza la carga automática de estilo zsh incluso si 'KSH_AUTOLOAD' está configurado por cualquier razón.
Después de que se haya resuelto, puede usar su nueva función 'hola':
Una palabra sobre el abastecimiento de estos archivos: eso está mal . Si obtiene ese archivo `~ / .zfunc / hello ', simplemente imprimirá" Hola mundo ". una vez. Nada mas. No se definirá ninguna función. Y además, la idea es cargar solo el código de la función cuando sea necesario . Después de la llamada de 'carga automática', la definición de la función no se lee. La función se marca para cargarse automáticamente más tarde según sea necesario.
Y finalmente, una nota sobre $ FPATH y $ fpath: Zsh los mantiene como parámetros vinculados. El parámetro en minúscula es una matriz. La versión en mayúsculas es un escalar de cadena, que contiene las entradas de la matriz vinculada unida por dos puntos entre las entradas. Esto se hace, porque manejar una lista de escalares es mucho más natural usando matrices, al tiempo que se mantiene la compatibilidad con versiones anteriores para el código que usa el parámetro escalar. Si elige usar $ FPATH (el escalar), debe tener cuidado:
funcionará, mientras que lo siguiente no funcionará:
La razón es que la expansión de tilde no se realiza entre comillas dobles. Esta es probablemente la fuente de tus problemas. Si
echo $FPATH
imprime una tilde y no una ruta expandida, entonces no funcionará. Para estar seguro, usaría $ HOME en lugar de una tilde como esta:Dicho esto, preferiría usar el parámetro de matriz como lo hice al principio de esta explicación.
Tampoco debe exportar el parámetro $ FPATH. Solo es necesario para el proceso de shell actual y no para ninguno de sus hijos.
Actualizar
Con respecto al contenido de los archivos en `$ fpath ':
Con la carga automática de estilo zsh, el contenido de un archivo es el cuerpo de la función que define. Así, un archivo llamado "hola" que contiene una línea
echo "Hello world."
define completamente una función llamada "hola". Eres libre de ponerhello () { ... }
el código, pero eso sería superfluo.Sin embargo, la afirmación de que un archivo solo puede contener una función no es del todo correcta.
Especialmente si observa algunas funciones del sistema de finalización basado en funciones (compsys), se dará cuenta rápidamente de que es un error. Usted es libre de definir funciones adicionales en un archivo de funciones. También es libre de hacer cualquier tipo de inicialización, que puede necesitar hacer la primera vez que se llama a la función. Sin embargo, cuando lo haga, siempre definirá una función que se denomina como el archivo en el archivo y llamará a esa función al final del archivo, por lo que se ejecuta la primera vez que se hace referencia a la función.
Si, con las subfunciones, no definió una función denominada como el archivo dentro del archivo, terminaría con esa función con definiciones de función (es decir, las de las subfunciones en el archivo). Definiría efectivamente todas sus subfunciones cada vez que llame a la función que se nombra como el archivo. Normalmente, eso no es lo que desea, por lo que redefiniría una función, que se llama como el archivo dentro del archivo.
Incluiré un esqueleto corto, que te dará una idea de cómo funciona:
Si ejecutara este ejemplo tonto, la primera ejecución se vería así:
Y las llamadas consecutivas se verán así:
Espero que esto aclare las cosas.
(Uno de los ejemplos más complejos del mundo real que usa todos esos trucos es la función ` _tmux ' ya mencionada del sistema de finalización basado en funciones de zsh).
fuente
my_function () { }
en tuHello world
ejemplo. Si la sintaxis no es necesaria, ¿cuándo sería útil usarla?El nombre del archivo en un directorio nombrado por un
fpath
elemento debe coincidir con el nombre de la función autocargable que define.Su función se llama
my_function
y~/.my_zsh_functions
es el directorio previsto en sufpath
, por lo que la definición demy_function
debe estar en el archivo~/.my_zsh_functions/my_function
.El plural en su nombre de archivo propuesto (
functions_1
) indica que estaba planeando poner múltiples funciones en el archivo. Este no es elfpath
trabajo de carga automática. Debe tener una definición de función por archivo.fuente
entregue
source ~/.my_zsh_functions/functions1
el terminal y evalúemy_function
, ahora podrá llamar a la funciónfuente
FPATH
yautoload
luego? ¿Por qué también necesito obtener el archivo? Ver mi pregunta actualizada.Puede "cargar" un archivo con todas sus funciones en su $ ZDOTDIR / .zshrc de esta manera:
O puede usar un punto "." en lugar de "fuente".
fuente
FPATH
yautoload
luego? ¿Por qué también necesito obtener el archivo? Ver mi pregunta actualizada.El aprovisionamiento definitivamente no es el enfoque correcto, ya que lo que parece querer es tener funciones de inicialización diferidas. Para eso
autoload
es eso . Así es como logras lo que buscas.En tu
~/.my_zsh_functions
, dices que quieres poner una función llamadamy_function
ese eco "hola mundo". Pero, lo envuelve en una llamada de función, que no es así como funciona. En cambio, necesita hacer un archivo llamado~/.my_zsh_functions/my_function
. En él, simplementeecho "Hello world"
, no en un contenedor de funciones. También podría hacer algo como esto si realmente prefiere tener el envoltorio.A continuación, en su
.zshrc
archivo, agregue lo siguiente:Cuando cargue un nuevo shell ZSH, escriba
which my_function
. Deberías ver esto:ZSH acaba de apagar mi_función para ti
autoload -X
. Ahora, corremy_function
pero solo escribemy_function
. Debería ver laHello world
impresión, y ahora, cuando ejecutewhich my_function
, debería ver la función completada así:Ahora, la verdadera magia viene cuando configuras toda tu
~/.my_zsh_functions
carpeta para trabajarautoload
. Si desea que todos los archivos que suelte en esta carpeta funcionen de esta manera, cambie lo que coloca en.zshrc
algo así:fuente