fzf: fuzzy finder universal para la terminal

fzf es un filtro interactivo de propósito general que lee líneas por stdin, presenta una interfaz de selección fuzzy en el terminal, y escribe la línea seleccionada por stdout. La palabra fuzzy aquí significa que no necesitas escribir la cadena exacta: si buscas ngcnf, fzf encuentra nginx.conf porque los caracteres aparecen en ese orden dentro de la cadena, aunque no sean consecutivos. El algoritmo pondera la coincidencia por proximidad y posición, así que los resultados más relevantes suben solos.

El diseño es intencionalmente simple: fzf no sabe nada de archivos, procesos ni historial. Solo filtra líneas. Toda su potencia viene de combinarlo con lo que ya genera tu shell — find, history, ps, git branch, lo que sea. Cuando el instalador oficial añade integraciones a tu .bashrc o .zshrc, lo que hace es redefinir atajos existentes para que pasen su salida por fzf antes de ejecutarse. El resultado es que Ctrl+R deja de ser una búsqueda secuencial por historial y se convierte en filtrado fuzzy instantáneo sobre todas las entradas a la vez.

Usarás fzf en cualquier situación donde tengas que seleccionar un elemento de una lista larga: un archivo enterrado en un árbol de directorios, una rama de git, un contenedor Docker, un proceso al que enviar una señal, una entrada de historial que recuerdas a medias. Si la lista tiene más de diez elementos y vas a elegir uno, fzf reduce el tiempo de selección a segundos.

Si configuras mal las integraciones — o no las activas — fzf queda instalado pero sin efecto en tu flujo de trabajo. El binario funciona, pero Ctrl+R sigue siendo el built-in de bash. Es el error más común: instalar sin sourcing el script de integración.

Instalación e integración completa

# Instalar fzf desde los repositorios de Debian Bookworm
sudo apt install fzf

# El paquete instala el binario pero NO activa las integraciones automáticamente.
# Hay que sourcing explícito. Añade esto a ~/.bashrc (o ~/.zshrc si usas zsh):

# --- bloque para ~/.bashrc ---
# Carga las key bindings: Ctrl+R (historial), Ctrl+T (archivos), Alt+C (directorios)
source /usr/share/doc/fzf/examples/key-bindings.bash

# Carga el completion fuzzy para comandos que lo soporten (kill, ssh, export, etc.)
source /usr/share/doc/fzf/examples/completion.bash

# Variables de entorno que controlan el comportamiento global de fzf
export FZF_DEFAULT_COMMAND='find . -type f -not -path "*/.git/*"'
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border --info=inline'

# Preview por defecto al usar Ctrl+T: muestra las primeras 100 líneas del archivo
export FZF_CTRL_T_OPTS='--preview "head -100 {}" --preview-window=right:50%:wrap'

# Para el historial (Ctrl+R), mostrar la entrada completa si es larga
export FZF_CTRL_R_OPTS='--preview "echo {}" --preview-window=down:3:wrap'
# --- fin del bloque ---

# Recarga la configuración en la sesión actual (en lugar de abrir terminal nueva)
source ~/.bashrc

# ── Uso básico: fzf sobre una lista arbitraria ──

# Seleccionar un archivo en el directorio actual y subdirectorios
# Ctrl+T en cualquier momento hace esto mismo, insertando la ruta en el prompt
selected=$(fzf)
echo "Seleccionaste: $selected"

# Abrir directamente en el editor el archivo elegido
vim $(fzf)

# ── Integración con pipes ──

# Seleccionar un proceso para matar (muestra PID + comando, mata el PID elegido)
# ps aux produce la lista; fzf filtra; awk extrae el PID; xargs lo pasa a kill
ps aux | fzf --header-lines=1 | awk '{print $2}' | xargs -r kill -15

# Seleccionar una rama de git y hacer checkout directamente
git branch | fzf | xargs git checkout

# Filtrar un log en tiempo real: las líneas nuevas aparecen en la lista
# (útil para buscar en logs grandes ya volcados, no para tail -f en vivo)
grep -i error /var/log/syslog | fzf

# ── fzf --preview: previsualizar antes de confirmar ──

# Buscar archivo de configuración con preview de su contenido completo
# bat da resaltado de sintaxis si está instalado; head es el fallback seguro
fzf --preview 'bat --style=numbers --color=always {} 2>/dev/null || head -50 {}'

# Buscar en el historial de apt y previsualizar el changelog del paquete elegido
# dpkg-query devuelve info del paquete; sirve para recordar qué instalaste y cuándo
grep ' install ' /var/log/dpkg.log | \
    awk '{print $NF}' | \
    sort -u | \
    fzf --preview 'dpkg-query -s {1} 2>/dev/null | head -20'

# ── Ctrl+R mejorado en acción ──
# Después de hacer source del key-bindings.bash, pulsa Ctrl+R en el prompt.
# Verás todas las entradas del historial filtrables en tiempo real.
# Escribe cualquier fragmento — parcial, desordenado — y fzf las ordena por relevancia.
# Enter ejecuta la línea seleccionada; Ctrl+E la pone en el prompt para editarla antes.

Qué está pasando en cada decisión

El source de los scripts en /usr/share/doc/fzf/examples/ es la pieza que más gente se salta. Sin él, fzf existe como binario pero ningún atajo de teclado cambia. Esos scripts redefinen las funciones de bash __fzf_history__ y __fzf_file__, y luego asignan Ctrl+R, Ctrl+T y Alt+C a ellas mediante bind. Si instalaste fzf con el script de instalación del repositorio de GitHub en lugar del paquete Debian, los scripts están en ~/.fzf/shell/ — diferente ruta, misma lógica.

FZF_DEFAULT_COMMAND define qué ejecuta fzf cuando lo llamas sin stdin explícito — es decir, cuando escribes fzf a secas en el prompt. El find del ejemplo excluye .git/ para no ahogarse en objetos internos de git. Si tienes fd instalado (apt install fd-find), es un reemplazo más rápido: export FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git'.

FZF_DEFAULT_OPTS con --layout=reverse pone el prompt de búsqueda arriba y los resultados debajo, que resulta más natural cuando fzf ocupa solo el 40% inferior del terminal (--height 40%). Sin --height, fzf toma toda la pantalla, lo cual interrumpe visualmente el flujo de trabajo.

En el ejemplo de ps aux | fzf --header-lines=1, la opción --header-lines=1 fija la primera línea (la cabecera de ps) para que no sea seleccionable ni desaparezca al filtrar. Ese detalle hace la diferencia entre una herramienta que se siente pulida y una que confunde.

El xargs -r en el pipe hacia kill es una salvaguarda: si fzf sale sin selección (pulsas Esc), no se ejecuta kill con argumentos vacíos. La -r significa “no ejecutar si stdin está vacío”. En sistemas donde xargs es de GNU coreutils — que es el caso en Debian — -r siempre está disponible.

El bloque de dpkg.log combina tres herramientas: extrae paquetes instalados del log, los deduplica con sort -u, y usa fzf con --preview para consultar el estado de cada paquete mientras navegas la lista. El {1} en el preview es el placeholder de fzf para la primera palabra del campo seleccionado — útil cuando la línea tiene prefijos que no quieres pasar al comando de preview.

FZF_CTRL_R_OPTS con --preview-window=down:3:wrap muestra solo tres líneas de preview para el historial, suficiente para ver comandos largos que no caben en el prompt pero sin que la ventana de preview domine la pantalla. El wrap evita el truncamiento horizontal.

[Ubuntu]: En Ubuntu 22.04+, el paquete fzf también existe en los repos oficiales, pero la ruta de los ejemplos puede estar en /usr/share/doc/fzf/examples/ igual que en Debian. Sin embargo, algunas instalaciones con snap o el script de GitHub dejan los archivos en ~/.fzf/, así que verifica con dpkg -L fzf o find ~/.fzf -name "*.bash" antes de hacer el source.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio