---
title: "Funciones y Comandos Personalizados en Fish Shell"
description: "Cómo crear, editar, guardar y autocargar funciones en Fish Shell. Cubre event handlers, parseo de argumentos, scope y ejemplos prácticos."
date: 2026-02-23
categories: ["vps"]
tags: ["fish-shell"]
---

import Notice from "@components/widgets/Notice.astro";
import Accordion from "@components/widgets/Accordion.astro";

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

```fish
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:

```fish
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:

```fish
function connect --argument-names host port
    ssh -p $port $host
end
```

### Agregar una descripción

```fish
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:

```fish
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:

```fish
# ~/.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

```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.

<Notice type="info" title="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á.
</Notice>

## Editar funciones

Fish tiene un editor de funciones integrado:

```fish
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:

```fish
functions weather
# o
type weather
```

## Ejemplos prácticos de funciones

### Atajo de Git con valores por defecto

```fish
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

```fish
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:

```fish
# ~/.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](/es/fish-shell-autocompletado-sugerencias/) para más detalles sobre cómo escribir completions.

### Backup con marca de tiempo

```fish
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

```fish
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

```fish
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

```fish
function __on_exit --on-event fish_exit
    echo "Goodbye!"
end
```

### Ejecutar código después de que un comando termina

```fish
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.

<Notice type="warning" title="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/`.
</Notice>

## 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:

```fish
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):

```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](/es/fish-shell-abreviaturas-vs-alias/).

## Gestión de funciones

```fish
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:

```fish
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](/es/fish-shell-autocompletado-sugerencias/) — escribir completions personalizados para tus funciones
- [Fish Shell abreviaturas vs alias](/es/fish-shell-abreviaturas-vs-alias/) — cuándo usar cada uno
- [Mejores plugins de Fish Shell](/es/mejores-plugins-fish-shell/) — amplía Fish con Fisher y plugins de la comunidad
- [Fish Shell en macOS](/es/fish-shell-macos-configuracion/) — si estás configurando Fish en un Mac
- [Instalar Fish Shell en Ubuntu](/es/instalar-fish-shell-ubuntu/) — primeros pasos en Linux