Cómo filtrar direcciones IP y rangos en logs Web usando solo Bash

Valencia, 2/09/2026, G.B.
Cuando administramos servidores web como Apache, Nginx o LiteSpeed, los archivos de acceso (access.log) se convierten rápidamente en la fuente principal para identificar tráfico no deseado, bots malintencionados o intentos de fuerza bruta.

Aunque existen herramientas de análisis y cortafuegos dinámicos, en muchas ocasiones necesitamos realizar una limpieza rápida de un archivo de log directamente desde la consola, sin instalar dependencias adicionales ni recurrir a lenguajes externos como Python o Perl.

En este artículo veremos cómo construir un script en Bash puro que nos permita eliminar líneas enteras de un log basándonos en direcciones IP individuales o rangos mediante expresiones regulares (regex).

La herramienta clave: grep en modo extendido

Para filtrar contenido en GNU/Linux descartando líneas completas, el comando por excelencia es grep. En lugar de buscar lo que queremos conservar, le indicamos lo que queremos excluir mediante el parámetro -v.

Para manejar rangos o múltiples patrones en una sola pasada, utilizaremos dos modificadores esenciales:

  • -v (--revert-match): Invierte el resultado de la búsqueda, conservando únicamente las líneas que no coinciden con el patrón.
  • -E (--extended-regexp): Activa las expresiones regulares extendidas, permitiéndonos usar operadores lógicos como la barra vertical (|) para el condicional «O» (OR) y corchetes [] para rangos numéricos.

Filtrado de rangos IP mediante Expresiones Regulares

A diferencia de las herramientas orientadas a red que interpretan notación CIDR (como /24), las utilidades del Shell procesan el archivo de log como texto plano. Por ello, traduciremos las subredes a expresiones regulares fijas.
A continuación, algunas equivalencias útiles para definir rangos dentro del patrón de filtrado:
Rango deseadoExpresión RegularExplicación
Subred /24 completa192\.168\.1\.Coincide con cualquier IP que comience por 192.168.1.
Subred /16 completa10\.0\.Coincide con cualquier IP que empiece por 10.0.
Rango .0 a .9172\.16\.0\.[0-9]Filtra del 172.16.0.0 al 172.16.0.9
Rango .10 a .99172\.16\.0\.[1-9][0-9]Filtra del 172.16.0.10 al 172.16.0.99
Rango .100 a .199172\.16\.0\.1[0-9][0-9]Filtra del 172.16.0.100 al 172.16.0.199
Nota: Es fundamental escapar los puntos (\.) con una barra invertida. De lo contrario, en expresiones regulares el punto actuaría como un comodín que representa cualquier carácter.

El Script Bash: filtrar_log.sh

A continuación se muestra la estructura completa del script. Este toma como entrada el archivo de log original y genera un nuevo archivo limpio sin las líneas asociadas a las IP definidas.
#!/bin/bash

# ==============================================================================
# Script de filtrado de IPs y rangos en logs de acceso
# Publicado en Indaga.net
# ==============================================================================

# Validar que se introduzcan los argumentos necesarios
if [ "$#" -ne 2 ]; then
    echo "Error: Argumentos insuficientes."
    echo "Uso: $0 <log_origen> <log_destino>"
    exit 1
fi

LOG_ORIGEN="$1"
LOG_DESTINO="$2"

# Verificar la existencia del archivo de origen
if [ ! -f "$LOG_ORIGEN" ]; then
    echo "Error: El archivo '$LOG_ORIGEN' no existe."
    exit 1
fi

# Definición de reglas y rangos a excluir (formato Regex)
PATRONES=(
    "192\.168\.1\."           # Subred 192.168.1.0/24
    "10\.0\."                  # Subred 10.0.0.0/16
    "172\.16\.0\.[0-9]"        # IPs del 172.16.0.0 al 172.16.0.9
    "172\.16\.0\.1[0-9]"       # IPs del 172.16.0.10 al 172.16.0.19
    "203\.0\.113\.45"          # Dirección IP única estática
)

# Unir el array de patrones utilizando la barra vertical (|) como separador OR
PATRON_REGEX=$(IFS='|'; echo "${PATRONES[*]}")

# Ejecución del filtrado con grep
grep -v -E "$PATRON_REGEX" "$LOG_ORIGEN" > "$LOG_DESTINO"

# Confirmación de salida
if [ $? -eq 0 ]; then
    echo "Filtrado completado con éxito."
    echo "Archivo limpio guardado en: $LOG_DESTINO"
else
    echo "Ocurrió un error al procesar el archivo."
fi

Modo de empleo

  1. Guardar el archivo: Crea el script en tu servidor, por ejemplo con nano filtrar_log.sh.
  2. Asignar permisos de ejecución:
    chmod +x filtrar_log.sh
    
  3. Ejecutar el proceso: Pasa como primer argumento el log actual y como segundo el nombre del archivo resultante:
    ./filtrar_log.sh /var/log/nginx/access.log /var/log/nginx/access_limpio.log
    

Ejecución rápida en una sola línea (One-Liner)

Si no necesitas la estructura del script y buscas solucionar una tarea puntual en la terminal, puedes ejecutar el filtro directamente concatenando los patrones deseados:
grep -v -E "192\.168\.1\.|10\.0\.|172\.16\.0\.[0-9]" access.log > access_filtrado.log
Esta alternativa utiliza únicamente las utilidades nativas de cualquier sistema POSIX, garantizando un rendimiento óptimo al procesar grandes volúmenes de texto sin sobrecargar los recursos del sistema.