Autocompletar Bash y zsh: cómo crear scripts de Tab completion

Cómo funciona el autocompletado con la tecla Tab
El autocompletado está en muchas interfaces: desde mensajería hasta IDEs. En Unix y Linux existe desde los años 80 y los shells como Bash y zsh ofrecen un ecosistema de completion muy capaz. El autocompletado reduce tecleo manual y errores.
- El autocompletado de comandos inspecciona la variable PATH para detectar comandos que coincidan con lo escrito.
- El autocompletado de nombres de archivo completa rutas absolutas o relativas y resuelve ambigüedades.
- El autocompletado de argumentos (subcomandos y opciones) actúa sobre lo que viene después del nombre del comando y puede ser más potente al ofrecer sugerencias contextuales.
En la práctica, el autocompletado de argumentos permite descubrir subcomandos, opciones y valores posibles sin consultar la documentación externa.
Añadir autocompletado a tus scripts
A continuación se explica cómo hacerlo en zsh primero y luego el equivalente en Bash. La idea general es: (1) declarar la lista de sugerencias posibles y (2) registrar una función/handler que devuelva esas sugerencias cuando el usuario pulse Tab.
Ejemplo de comando
Usaremos un script de ejemplo que gestiona una lista de tareas (to-dos). El objetivo es ofrecer autocompletado para subcomandos sencillos como edit y help. El fragmento relevante es este:
#!/usr/bin/env zsh
FILE="$HOME/.local/state/todos/data"
if [ "$#" -eq "1" ] && [ "$1" = "edit" ] ; then
"${EDITOR:-vi}" "$FILE"
elif [ "$#" -eq "1" ] && [ "$1" = "help" ] ; then
echo "Usage: $(basename $0) [ edit | help ]"
else
<"$FILE" grep -v ^~
fi
Guarda este script como todos (o todos.sh si lo prefieres) y ponlo ejecutable en tu PATH. Los comportamientos básicos que buscamos son:
- todos: mostrar la lista de tareas (ignorando líneas que empiezan por ~)
- todos help: mostrar la ayuda
- todos edit: abrir el archivo de datos en el editor
El autocompletado solo mejora la experiencia: no altera la lógica del script.
Script de autocompletado mínimo para zsh
En zsh el mecanismo es sencillo y el ejemplo mínimo se ve así:
_complete_todos() {
compadd help edit
}
autoload -Uz compinit
compinit
compdef _complete_todos todos
- _complete_todos es la función que añade sugerencias mediante compadd.
- compadd es parte del módulo compinit de zsh.
- compinit debe cargarse y compdef conecta la función con el comando todos.
Puedes poner este fragmento en tu ~/.zshrc o en un archivo de fpath cuyo nombre empiece por “_” y que zsh lea.
Diferencias en Bash
Bash maneja completion de forma distinta: espera que el handler devuelva las sugerencias en la variable COMPREPLY. Un ejemplo ingenuo que lista todas las opciones siempre es:
_complete_todos_bash() {
COMPREPLY=(help edit)
}
complete -F _complete_todos_bash todos
Problema: Bash no filtra por lo escrito hasta ahora, así que si el usuario teclea “he” seguirá devolviendo “help edit”. Para dar sugerencias contextuales hay que usar variables que Bash exporta cuando se pulsa Tab:
- COMP_WORDS: array con las palabras completas del comando.
- COMP_CWORD: índice de la palabra actual donde está el cursor.
Además, Bash incluye compgen, que puede filtrar una lista estática según lo escrito:
$ compgen -W "one two three" o
one
$ compgen -W "one two three" t
two
three
Usando compgen para proporcionar sugerencias contextuales:
_complete_todos_bash() {
COMPREPLY=( $( compgen -W "edit help" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
complete -F _complete_todos_bash todos
Este handler devolverá solo las opciones que coincidan con lo que el usuario ha tecleado hasta ese momento.
Versión portátil (zsh y Bash)
Para scripts que compartirás entre sistemas, detecta el shell invocador y registra el handler correspondiente. Un ejemplo completo:
SUBCOMMANDS=(help edit halt)
_complete_todos_zsh() {
compadd $SUBCOMMANDS
}
_complete_todos_bash() {
COMPREPLY=( $( compgen -W "${SUBCOMMANDS[*]}" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
if [ -n "${ZSH_VERSION:-}" ]; then
autoload -Uz compinit
compinit
compdef _complete_todos_zsh todos
elif [ -n "${BASH_VERSION:-}" ]; then
complete -F _complete_todos_bash todos
fi
Notas clave:
- ZSH_VERSION y BASH_VERSION indican en qué shell estamos.
- El shell que importa es el que invoca el autocompletado (donde el usuario pulsa Tab). No importa en qué shell se escribió el script original.
- SUBCOMMANDS contiene la fuente única de verdad para las sugerencias; ambos handlers la usan.
Guarda esto en completion.sh y sourcea el archivo desde ~/.bashrc y/o ~/.zshrc:
. /ruta/a/completion.sh
Buenas prácticas y recomendaciones
- Mantén la lógica de generación de sugerencias fuera del handler si es costosa (cacharrea resultados y reutilízalos). Evita comandos lentos en cada pulsación de Tab.
- Si la lista es dinámica (p. ej. nombres de ramas en Git), invoca la fuente en tiempo real pero con límites o caching para no bloquear la shell.
- Respeta las convenciones del shell: en zsh usa compadd y funciones con prefijo _; en bash, usa complete y COMPREPLY.
- Proporciona completions para opciones largas y cortas (–help y -h) si tu programa las soporta.
- Documenta cómo instalar el completion en tu proyecto (ubicación recomendada y cómo activar).
Important: Evita ejecutar operaciones destructivas desde la lógica de completado; solo consulta y lista valores.
Cuándo falla o limitaciones comunes
- Scripts que dependen de una configuración de entorno que no está disponible cuando se ejecuta el handler pueden producir errores.
- Llamar a comandos remotos o que requieren autenticación interactiva desde el autocompletado puede dejar la shell esperando; en su lugar, haz una lista local o cachea los resultados.
- Bash no aplica filtrado automático: si el handler no filtra según COMP_WORDS, el usuario recibirá demasiadas sugerencias.
Alternativas y herramientas útiles
- bash-completion: colección amplia de completions para muchos comandos; puedes inspirarte en su código.
- omz (Oh My Zsh) y sus plugins: proveen completions y patrones para zsh.
- fpath y archivos con nombre que empieza por “_” en zsh para mantener completions organizados.
Mini-metodología para crear un completion útil (5 pasos)
- Identifica los subcomandos y opciones que vas a soportar.
- Diseña una función que devuelva la lista completa para pruebas locales.
- Añade filtrado por el texto ya tecleado (compgen en Bash, compadd para zsh con palabras filtradas por el shell).
- Prueba en un entorno real (sourcear desde ~/.bashrc o ~/.zshrc) y ajusta comportamiento.
- Añade caching si la generación de opciones es costosa y documenta la instalación.
Role-based checklist
Desarrollador:
- Definir SUBCOMMANDS y opciones admitidas.
- Probar completions en Bash y zsh.
- Evitar operaciones lentas en el handler.
Administrador de sistemas:
- Distribuir el archivo completion.sh en /etc/bash_completion.d/ o en el fpath de zsh.
- Verificar permisos y rutas de instalación para usuarios.
Usuario final:
- Sourcear el script en ~/.bashrc o ~/.zshrc.
- Confirmar que Tab muestra sugerencias y que coinciden con la ayuda del comando.
Pruebas y criterios de aceptación
- Al pulsar Tab con la palabra vacía tras el comando, deben aparecer todas las opciones previstas.
- Al pulsar Tab tras teclear un prefijo, solo deben aparecer las opciones que coincidan con ese prefijo.
- El handler no debe introducir retardos perceptibles (>200 ms) para opciones comunes; si lo hace, debe cachear.
- La instalación mediante sourcing debe ser reproducible en Bash y zsh.
Árbol de decisión para elegir enfoque (Mermaid)
flowchart TD
A[¿Tu script es usado solo por ti?] -->|Sí| B[Usar completion simple en ~/.bashrc o ~/.zshrc]
A -->|No| C[¿Compartir con otros sistemas?]
C -->|Sí| D[Crear completion portátil 'detectar shell']
C -->|No| B
D --> E{¿Necesitas completions dinámicos?}
E -->|No| F[LISTA estática en SUBCOMMANDS]
E -->|Sí| G[Implementar función que consulte origen + cache]
G --> H[Evitar llamadas remotas sin timeout]
Ejemplos avanzados y casos de uso
- Autocompletar nombres de rama: llama a git branch –list y parsea resultados (cachea para no repetir la consulta en cada pulsación).
- Opciones con valores: para opciones como –format=, el handler puede ofrecer los formatos soportados.
- Completions condicionados: si el primer subcomando es init, las opciones del segundo subcomando pueden ser distintas. Usa COMP_WORDS/COMP_CWORD para decidir.
Snippet avanzado (idea): generar completions dinámicos con cache simple en Bash:
CACHE_FILE="$HOME/.cache/todos_subcommands"
generate_subcommands() {
if [ -f "$CACHE_FILE" ] && [ $(find "$CACHE_FILE" -mmin -5) ]; then
cat "$CACHE_FILE"
else
# ejemplo: consulta remota o cálculo costoso
echo "help edit halt" > "$CACHE_FILE"
cat "$CACHE_FILE"
fi
}
_complete_todos_bash() {
local list=$(generate_subcommands)
COMPREPLY=( $( compgen -W "$list" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
Este patrón evita repetir operaciones caras y mantiene respuestas rápidas.
Notas de compatibilidad y migración
- zsh: aprovecha compinit/compadd y la estructura de fpath. Colocar archivos con nombre que comience por “_” en un directorio del fpath permite activar completions automáticamente.
- bash: en distribuciones con bash-completion instalado, coloca los scripts en /etc/bash_completion.d/ o pide a los usuarios que hagan source manual.
- Prueba tu completion con distintas versiones de Bash/zsh si puedes: algunas funciones avanzadas de zsh no están presentes en versiones muy antiguas.
1-line glosario
- COMP_WORDS: array que contiene las palabras del comando actual en Bash.
- COMP_CWORD: índice de la palabra que se está completando en Bash.
- compadd: función de zsh para añadir sugerencias al completion.
- compinit: módulo de zsh que inicializa el sistema de completado.
- compgen: utilidad de Bash para generar posibles completions a partir de una lista.
Resumen
Crear autocompletado para tus scripts mejora la usabilidad y la eficiencia. Para zsh usa compadd y compinit; para Bash usa complete, COMPREPLY y compgen para filtrar por prefijo. Para compartir, escribe una capa de detección de shell y mantén la lógica de generación de sugerencias clara y rápida.
Important: Siempre evita operaciones interactivas o costosas en el handler; cachea resultados dinámicos y documenta cómo instalar el completion para tus usuarios.
Fin.
Materiales similares

Crear Video Overviews en NotebookLM

Detener apps en segundo plano en Android
Reducir array RAID degradado (/dev/md1)

Audio ausente en Historias de Instagram en iPhone: solución

Rastrear y protegerte de números telefónicos falsos
