Funciones y Comandos Personalizados en Fish Shell
Cómo crear, editar, guardar y autocargar funciones en Fish Shell. Cubre event handlers, parseo de argumentos, scope y ejemplos prácticos.
Las funciones en Fish son la forma de construir comandos reutilizables. Si ya usaste funciones en Bash, la idea es la misma, pero la implementación de Fish es más limpia — sin llaves, manejo explícito de argumentos a través de $argv, y un sistema de carga diferida (lazy-loading) que mantiene el arranque rápido.
Uso funciones para todo, desde atajos rápidos hasta herramientas específicas de proyecto. Esta guía cubre cómo crearlas, guardarlas permanentemente y las características propias de Fish que las hacen más útiles que las funciones de Bash.
Crear una función básica
function greet
echo "Hello, $argv"
end
Ejecuta greet World e imprime Hello, World. La variable $argv contiene todos los argumentos pasados a la función. Puedes acceder a argumentos individuales con $argv[1], $argv[2], etc.
Esa función solo dura la sesión actual del shell. Cierra la terminal y desaparece. Enseguida explico cómo hacer funciones permanentes.
Funciones con argumentos con nombre
Fish no tiene parámetros con nombre como Python, pero --argument-names ofrece algo parecido:
function mkcd --argument-names dir
mkdir -p $dir
cd $dir
end
Ahora mkcd projects/new-app crea el directorio y te mueve a él. El primer argumento se asigna a $dir. Los argumentos extra siguen disponibles a través de $argv.
Puedes listar múltiples nombres de argumento:
function connect --argument-names host port
ssh -p $port $host
end
Agregar una descripción
function ll --description "List files in long format"
ls -la $argv
end
La descripción aparece cuando ejecutas functions o type ll. Es documentación para tu yo del futuro.
Guardar funciones permanentemente
Fish tiene tres formas de conservar funciones entre sesiones.
Método 1: funcsave (la forma Fish)
Crea una función interactivamente y luego guárdala:
function weather --argument-names city
curl "wttr.in/$city?format=3"
end
funcsave weather
Esto guarda la función en ~/.config/fish/functions/weather.fish. Fish la carga automáticamente cuando usas el comando en cualquier sesión futura — no al arrancar, sino bajo demanda. Esta carga diferida es la razón por la que Fish se mantiene rápido sin importar cuántas funciones guardadas tengas.
Método 2: Crear el archivo directamente
Escribe el archivo de la función tú mismo:
# ~/.config/fish/functions/weather.fish
function weather --argument-names city
curl "wttr.in/$city?format=3"
end
Mismo resultado que funcsave. Prefiero este método para funciones que quiero versionar con mis dotfiles.
Método 3: Ponerla en config.fish
# ~/.config/fish/config.fish
function weather --argument-names city
curl "wttr.in/$city?format=3"
end
Funciona, pero tiene dos desventajas: la función se carga en cada arranque del shell (no de forma diferida), y tu config.fish se hace más largo. Usa archivos de autocarga para cualquier función que no sea trivial.
Reglas de autocarga
Para que la autocarga funcione, el nombre del archivo debe coincidir con el nombre de la función. Una función llamada weather debe estar en weather.fish. Si el archivo contiene múltiples funciones, solo la que coincida con el nombre del archivo se autocargará.
Editar funciones
Fish tiene un editor de funciones integrado:
funced weather
Esto abre la función en $EDITOR (o $VISUAL). Cuando guardas y cierras el editor, Fish carga la función actualizada en tu sesión actual. Luego puedes hacerla permanente con funcsave weather.
Para ver la definición actual de una función sin editarla:
functions weather
# o
type weather
Ejemplos prácticos de funciones
Atajo de Git con valores por defecto
function gc --description "Git commit with message"
if test (count $argv) -eq 0
echo "Usage: gc <message>"
return 1
end
git add --all
git commit -m "$argv"
end
Uso: gc "fix login redirect" añade todo al staging y hace commit con ese mensaje.
Cambio rápido de proyecto
function proj --argument-names name
set -l base ~/projects
if test -z "$name"
ls $base
return
end
if test -d $base/$name
cd $base/$name
else
echo "Project '$name' not found in $base"
return 1
end
end
Ejecuta proj para listar proyectos, o proj myapp para saltar a ~/projects/myapp. También puedes agregar completado con Tab:
# ~/.config/fish/completions/proj.fish
complete -c proj -f -a "(ls ~/projects)"
Ahora proj seguido de Tab lista tus directorios de proyecto. Consulta mi guía de autocompletado para más detalles sobre cómo escribir completions.
Backup con marca de tiempo
function bak --argument-names file
if test -z "$file"
echo "Usage: bak <file>"
return 1
end
cp $file $file.bak.(date +%Y%m%d-%H%M%S)
end
bak config.yaml crea config.yaml.bak.20260224-141500.
Limpieza de Docker
function docker-clean --description "Remove stopped containers, dangling images, unused volumes"
echo "Removing stopped containers..."
docker container prune -f
echo "Removing dangling images..."
docker image prune -f
echo "Removing unused volumes..."
docker volume prune -f
end
Event handlers
Las funciones pueden responder a eventos. Esto es útil para ejecutar código cuando cambian variables, cuando un comando termina o cuando Fish se cierra.
Ejecutar código cuando cambia una variable
function __on_pwd_change --on-variable PWD
if test -f .node-version
echo "Node version: "(cat .node-version)
end
end
Cada vez que cambias de directorio, esto verifica si existe un archivo .node-version. El flag --on-variable PWD dispara la función cada vez que $PWD cambia.
Ejecutar código al salir de Fish
function __on_exit --on-event fish_exit
echo "Goodbye!"
end
Ejecutar código después de que un comando termina
function __notify_long_command --on-event fish_postexec
if test $CMD_DURATION -gt 10000
echo "Command took "(math $CMD_DURATION / 1000)" seconds"
end
end
Esto imprime un aviso cuando cualquier comando tarda más de 10 segundos. $CMD_DURATION es una variable especial de Fish que contiene el tiempo de ejecución del último comando en milisegundos.
Nombres de event handlers
Las funciones de event handler deberían empezar con doble guion bajo o un prefijo único para evitar colisiones de nombres. Además, los event handlers en archivos de autocarga no se dispararán hasta que la función se haya cargado una vez. Para handlers que necesiten funcionar desde el inicio, ponlos en config.fish o conf.d/.
Scope y visibilidad de variables
Las funciones tienen su propio scope local por defecto. Las variables definidas con set -l dentro de una función no son visibles fuera de ella:
function test_scope
set -l secret "hidden"
echo $secret
end
test_scope # prints "hidden"
echo $secret # prints nothing
Usa set -g para variables globales (visibles en toda la sesión) o set -U para variables universales (persisten en todas las sesiones de Fish):
set -g session_var "I last until you close this terminal"
set -U persistent_var "I survive restarts"
Funciones vs abreviaturas vs alias
Fish tiene tres formas de crear atajos. Aquí cuándo usar cada una:
| Funciones | Abreviaturas | Alias | |
|---|---|---|---|
| Mejor para | Lógica compleja, comandos multilínea | Atajos de comandos simples | Wrapping simple de comandos |
| Expansión | Sin expansión, se ejecuta tal cual | Se expande en la línea de comandos antes de ejecutar | Se envuelve como función internamente |
| El historial muestra | Nombre de la función | Comando expandido | Nombre del alias |
| Argumentos | Manejo completo con $argv | Limitado (basado en posición/regex) | Pass-through con $argv |
Uso abreviaturas para atajos simples (gs → git status), y funciones para cualquier cosa que necesite lógica. Cubrí las abreviaturas vs alias en detalle en Fish Shell abreviaturas vs alias.
Gestión de funciones
functions # list all defined functions
functions -n # list function names only
functions weather # show a function's definition
functions -e weather # erase a function
funcsave weather # save to autoload file
funced weather # edit in $EDITOR
Para eliminar una función guardada permanentemente:
functions -e weather
funcsave weather
El segundo comando escribe el estado “borrado”, eliminando el archivo de ~/.config/fish/functions/.
Guías relacionadas
- Autocompletado y sugerencias en Fish Shell — escribir completions personalizados para tus funciones
- Fish Shell abreviaturas vs alias — cuándo usar cada uno
- Mejores plugins de Fish Shell — amplía Fish con Fisher y plugins de la comunidad
- Fish Shell en macOS — si estás configurando Fish en un Mac
- Instalar Fish Shell en Ubuntu — primeros pasos en Linux