fnmatch en Python: filtra nombres de archivos

Publicado el: 10/08/2026
Tempo de leitura: 5 minutos
Carpeta y lupa que representan filtros de nombres con fnmatch en Python

El módulo fnmatch de la biblioteca estándar compara nombres de archivos con patrones de comodines similares a los usados por shells Unix. Es útil cuando una aplicación ya dispone de una colección de nombres y necesita seleccionar elementos como *.py, informe-202?.csv o imagen-[0-9].png. A diferencia de glob, no recorre directorios. A diferencia de re, sus patrones no son expresiones regulares.

Esta guía explica fnmatch(), fnmatchcase(), filter(), filterfalse() y translate(), junto con prácticas de portabilidad, rendimiento y seguridad.

Sintaxis de los comodines

La sintaxis tiene cuatro construcciones principales. El asterisco coincide con cualquier cantidad de caracteres, el signo de interrogación con exactamente uno, [abc] acepta un carácter de la secuencia y [!abc] excluye los indicados.

import fnmatch

print(fnmatch.fnmatch("informe-2026.csv", "informe-*.csv"))
print(fnmatch.fnmatch("foto-7.jpg", "foto-?.jpg"))
print(fnmatch.fnmatch("log-a.txt", "log-[abc].txt"))

Para buscar literalmente un metacarácter, colócalo entre corchetes. El patrón [?], por ejemplo, coincide con un signo de interrogación real.

Filtrar una colección existente

fnmatch.filter() recibe un iterable de nombres y devuelve solamente los que coinciden. Expresa la intención con claridad y está implementado de forma más eficiente que repetir manualmente la misma comparación.

from fnmatch import filter

nombres = ["app.py", "test.py", "README.md", "datos.csv"]
python = filter(nombres, "*.py")
print(python)

El patrón funciona con os.listdir(), resultados de APIs, registros de bases de datos, entradas de archivos comprimidos, claves de almacenamiento y listas recibidas de otro servicio.

Excluir coincidencias con filterfalse

Python 3.14 añadió filterfalse(), que devuelve los nombres que no coinciden. Así se evitan comprensiones negadas repetitivas y las políticas de exclusión quedan más claras.

from fnmatch import filterfalse

archivos = ["a.tmp", "b.txt", "c.log", "d.tmp"]
permanentes = filterfalse(archivos, "*.tmp")
print(permanentes)

En versiones anteriores, usa una comprensión con not fnmatch.fnmatch(nombre, patron).

Mayúsculas según el sistema operativo

fnmatch() aplica os.path.normcase() al nombre y al patrón. Por eso el resultado puede cambiar entre sistemas. En plataformas que normalizan mayúsculas, ARCHIVO.TXT puede coincidir con *.txt; en sistemas sensibles a mayúsculas normalmente no.

Usa fnmatchcase() cuando la política deba comportarse igual en Linux, Windows, macOS, contenedores y CI. Realiza una comparación sensible a mayúsculas sin normalización del sistema.

from fnmatch import fnmatchcase

permitido = fnmatchcase("Informe.CSV", "*.csv")
print(permitido)  # False

Los separadores de directorio son caracteres normales

La barra no recibe tratamiento especial en fnmatch. Un asterisco puede atravesar separadores presentes en la cadena. Esto difiere de la expansión de rutas, donde glob procesa segmentos.

import fnmatch

print(fnmatch.fnmatch("datos/2026/ventas.csv", "*.csv"))

Usa pathlib.Path.glob() o glob para recorrer el sistema de archivos, aplicar recursividad o respetar segmentos. Usa fnmatch cuando ya tienes los nombres y solo necesitas comparación textual.

Archivos ocultos

Los nombres que comienzan con punto no son especiales. Un patrón como * puede coincidir con .env, .gitignore y otros archivos ocultos. La aplicación debe definir esta política explícitamente.

def visible(nombre):
    return not nombre.startswith(".")

seleccionados = [n for n in nombres if visible(n) and fnmatch.fnmatch(n, "*")]

fnmatch no es regex

El patrón *.txt es válido en fnmatch, mientras que en una expresión regular el asterisco modifica el token anterior. Los grupos, capturas, lookarounds y cuantificadores numéricos de regex no están disponibles en los comodines.

Los comodines suelen ser mejores para reglas legibles sobre nombres. Usa re cuando necesites capturar grupos, imponer estructura compleja o validar límites precisos.

Traducir el patrón a regex

translate() convierte la sintaxis de shell en una expresión regular. Puede servir para compilar el resultado, integrarlo en otra etapa o inspeccionar la regla generada.

import fnmatch
import re

regex = re.compile(fnmatch.translate("informe-*.csv"))
print(bool(regex.match("informe-julio.csv")))

Trata la cadena generada como detalle de implementación. No dependas de su representación exacta entre versiones de Python.

Caché y rendimiento

Las funciones principales mantienen una caché tipada de expresiones compiladas con un máximo de 32.768 patrones. Reutilizar un conjunto pequeño y estable es eficiente. En cambio, recibir patrones únicos de usuarios continuamente reduce el beneficio de la caché.

En servicios públicos limita longitud y cantidad de patrones. Evita comparar colecciones enormes contra miles de reglas arbitrarias en una sola solicitud. Aplica filtros baratos primero, pagina resultados y mide cargas reales.

Cadenas y bytes

Las APIs aceptan cadenas Unicode o bytes codificados en ISO-8859-1, pero nombre y patrón deben tener el mismo tipo. Mezclar bytes con str genera error. Las aplicaciones modernas normalmente deben normalizar todo a Unicode.

import fnmatch

print(fnmatch.fnmatch(b"datos.csv", b"*.csv"))
# fnmatch.fnmatch(b"datos.csv", "*.csv")  # TypeError

Límites de seguridad

fnmatch solamente compara texto. No confirma que el archivo exista, no evita path traversal, no impone permisos y no garantiza que una ruta permanezca dentro de un directorio autorizado. Una coincidencia positiva nunca debe ser la única autorización antes de leer, mover, subir o borrar.

Resuelve rutas con pathlib, verifica el directorio base, rechaza componentes inesperados y aplica controles de acceso reales. Para operaciones destructivas por lotes, muestra una vista previa y registra los nombres seleccionados.

Ejemplo: seleccionar logs

from fnmatch import fnmatchcase
from pathlib import Path

BASE = Path("logs").resolve()
PATRONES = ("app-*.log", "worker-*.log")

def seleccionar_logs():
    resultado = []
    for ruta in BASE.iterdir():
        if not ruta.is_file():
            continue
        if any(fnmatchcase(ruta.name, p) for p in PATRONES):
            resultado.append(ruta)
    return resultado

El código compara únicamente ruta.name, por lo que los directorios no alteran la semántica. La aplicación controla los patrones y verifica por separado que cada resultado sea un archivo.

Errores frecuentes

  • Esperar el mismo comportamiento de mayúsculas en todos los sistemas.
  • Confundir comodines con expresiones regulares.
  • Suponer que el asterisco se detiene en las barras.
  • Olvidar que los archivos ocultos coinciden con patrones normales.
  • Usar una coincidencia como decisión de autorización.
  • Mezclar cadenas y bytes.
  • Usar fnmatch para recorrer directorios en lugar de glob.

Buenas prácticas

  • Elige fnmatchcase() para políticas portables.
  • Compara solo el nombre base cuando los directorios no importen.
  • Define explícitamente el tratamiento de archivos ocultos.
  • Limita patrones proporcionados por usuarios.
  • Valida rutas y permisos por separado.
  • Prueba Unicode, mayúsculas, nombres vacíos y límites.
  • Usa filter() y filterfalse() para colecciones completas.

Guías relacionadas

Continúa con nuestras guías de fileinput en Python, linecache en Python, shlex en Python, filecmp en Python y bisect en Python.

Las referencias oficiales son la documentación de fnmatch y la documentación de glob.

Conclusión

fnmatch es una solución enfocada para comparar nombres existentes con reglas de comodines legibles. Su API pequeña, caché interna y filtrado inverso de Python 3.14 lo hacen útil para filtros y políticas. El uso correcto exige separar la coincidencia de la expansión de rutas, regex, autorización y validación de caminos.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Monitor con datos binarios que representa arrays numéricos compactos en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    array en Python: números compactos

    Aprende array en Python para almacenar números compactos, usar archivos binarios, byte order, memoryview y buffers seguros.

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Círculo cromático que representa conversiones RGB, HSV y HLS con colorsys en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    colorsys en Python: RGB, HSV y HLS

    Aprende colorsys en Python para convertir colores entre RGB, HSV, HLS y YIQ, crear paletas y evitar errores de escala

    Ler mais

    Tempo de leitura: 5 minutos
    09/08/2026
    Icono de configuración que representa archivos plist con plistlib en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    plistlib en Python: archivos plist

    Aprende plistlib en Python para leer y escribir archivos plist XML y binarios, validar datos y manejar fechas, bytes y

    Ler mais

    Tempo de leitura: 6 minutos
    08/08/2026
    Candado digital que representa credenciales por host con netrc en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    netrc en Python: credenciales por host

    Aprende netrc en Python para leer credenciales por host, validar permisos, tratar errores e integrar clientes de red de forma

    Ler mais

    Tempo de leitura: 7 minutos
    08/08/2026
    Mensaje digital que representa codificación quoted-printable con quopri en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    quopri en Python: quoted-printable

    Aprende quopri en Python para codificar y decodificar quoted-printable en correo, archivos e integraciones MIME de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    08/08/2026
    Icono de archivo digital que representa tipos MIME con mimetypes en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    mimetypes en Python: tipos MIME

    Aprende mimetypes en Python para identificar tipos MIME, extensiones y encodings de forma segura en cargas, descargas, correo y APIs

    Ler mais

    Tempo de leitura: 6 minutos
    08/08/2026