Perl para el día a día del sysadmin: logs, procesos y one-liners (Parte II)

En 2008, el programador letón Peteris Krumins —conocido en su blog como «catonmat»— empezó a publicar una serie titulada «Perl One-Liners Explained», diseccionando línea a línea decenas de comandos de una sola línea capaces de hacer en Perl lo que normalmente exigiría encadenar grep, sed, awk y cut en un pipeline largo y frágil. Esa serie sigue circulando y citándose hoy, casi veinte años después, en foros de sysadmins que se la pasan unos a otros como quien comparte un truco de cocina que nunca falla. No es nostalgia: es que el problema que resuelve —convertir texto desordenado en información útil, deprisa, desde la propia terminal— no ha dejado de aparecer ni un solo día desde entonces.

En la Parte I vimos de dónde viene Perl, por qué sigue instalado en cualquier distribución Linux y la sintaxis mínima para no perderte. En esta segunda entrega vamos a lo que de verdad le importa a quien administra sistemas: usar Perl para leer y filtrar logs, vigilar procesos y automatizar comprobaciones básicas del estado del sistema, con ejemplos que puedes copiar y ejecutar ahora mismo.


El one-liner: la razón por la que Perl sigue en tu caja de herramientas

Antes de escribir un solo script guardado en un fichero, vale la pena dominar el modo en el que más se usa Perl en el día a día de un sysadmin: como comando suelto en la terminal, con la opción -e para ejecutar código directamente. Tres de las opciones que verás por todas partes son -n, -p y -i.

Con -n, Perl envuelve tu código en un bucle implícito que lee el fichero (o la entrada estándar) línea a línea, sin imprimir nada salvo que se lo pidas explícitamente. Es el equivalente casi directo de grep cuando lo combinas con una condición:

perl -ne 'print if /ERROR/' /var/log/syslog

Esta única línea recorre el fichero de log y muestra solo las que contienen «ERROR» — el mismo resultado que grep ERROR /var/log/syslog, pero con la ventaja de que en cuanto necesitas algo más elaborado que un patrón simple (extraer un campo, contar apariciones, transformar el texto), ya estás en el mismo lenguaje y no tienes que saltar a otra herramienta.

Con -p, Perl hace lo mismo pero imprime automáticamente $_ (la variable que contiene la línea actual) al final de cada vuelta del bucle, lo que lo convierte en el sustituto natural de sed para sustituciones:

perl -pe 's/192\.168\.1\.\d+/[IP-INTERNA]/g' acceso.log

Esto anonimiza cualquier dirección IP de la red interna 192.168.1.x en el log, sustituyéndola por una etiqueta fija, sin tocar el resto de la línea. Y si además añades -i, la sustitución se hace directamente sobre el fichero en lugar de imprimir el resultado por pantalla — con -i.bak en vez de -i a secas, Perl guarda una copia del original con la extensión .bak antes de modificarlo, lo cual conviene hacer siempre la primera vez que pruebas una sustitución sobre un fichero que te importa.

       LEER LÍNEA A LÍNEA           MISMO BUCLE + IMPRIME
       ══════════════════           ══════════════════════
perl -ne '...'                 perl -pe '...'
     │                               │
     ▼                               ▼
 while (<>) {                   while (<>) {
     ...código...                   ...código...
 }                                   print;
                                 }

Contar y agrupar: el hash como aliado para analizar logs

Donde Perl empieza a marcar diferencia frente a herramientas puramente de línea de comandos es en tareas que requieren «recordar» algo mientras se procesa el fichero — por ejemplo, contar cuántas veces aparece cada dirección IP en un log de acceso web, el ejercicio clásico de cualquier análisis de tráfico:

perl -ne '
    if (/^(\d+\.\d+\.\d+\.\d+)/) {
        $conteo{$1}++;
    }
    END {
        foreach my $ip (sort { $conteo{$b} <=> $conteo{$a} } keys %conteo) {
            print "$ip: $conteo{$ip}\n";
        }
    }
' acceso.log

Este comando extrae la IP al principio de cada línea con una expresión regular, la usa como clave de un hash llamado %conteo y va incrementando su valor cada vez que aparece. El bloque END se ejecuta una sola vez, después de procesar todo el fichero, y en ese momento ordena el hash de mayor a menor número de apariciones para mostrar qué IPs han generado más tráfico. Es exactamente el tipo de tarea para la que un hash —una estructura de clave-valor nativa del lenguaje, sin necesidad de importar nada— hace que Perl se sienta como si estuviera hecho a medida para analizar logs, porque en la práctica es así.

Si el log tiene columnas separadas por un carácter fijo (comas, tabulaciones, espacios), la opción -a activa el «autosplit»: Perl trocea automáticamente cada línea en el array @F, y con -F puedes indicar el separador exacto:

perl -ane 'print "$F[0] hizo $F[6] peticiones a $F[8]\n" if $F[8] eq "/login"' acceso.log

Aquí $F[0] sería, por ejemplo, la IP (el primer campo tras el troceo), y $F[8] la ruta solicitada en un log en formato común de servidor web — conviene siempre comprobar primero, con head -1 acceso.log, en qué posición cae cada campo del formato de log real que tengas delante, porque varía entre Apache, Nginx y otros.

Vigilar procesos y el estado del sistema sin salir de Perl

Perl no necesita ningún módulo adicional para leer el pseudosistema de archivos /proc de Linux, que es donde el kernel expone en tiempo real el estado de la carga, la memoria y cada proceso en ejecución. Por ejemplo, para leer la carga media del sistema:

#!/usr/bin/perl
use strict;
use warnings;

open(my $fh, '<', '/proc/loadavg') or die "No puedo leer /proc/loadavg: $!";
my $linea = <$fh>;
close($fh);

my ($carga1, $carga5, $carga15) = split(' ', $linea);
print "Carga últimos 1/5/15 min: $carga1 / $carga5 / $carga15\n";

if ($carga1 > 4.0) {
    print "AVISO: carga elevada\n";
}

Este pequeño script abre /proc/loadavg, lee su única línea, la trocea con split en sus tres valores de carga media, y avisa si la carga del último minuto supera un umbral. Es deliberadamente sencillo, pero es exactamente el esqueleto sobre el que se construyen muchísimos scripts de comprobación caseros que luego se lanzan desde cron cada pocos minutos, antes de que exista o en paralelo a una herramienta de monitorización más completa como las que se comentan en otros artículos de este blog.

El mismo patrón —abrir un fichero de /proc, leerlo, extraer lo que interesa con una expresión regular o un split— sirve para memoria (/proc/meminfo), para listar procesos recorriendo los directorios numéricos de /proc/<pid>/, o para combinarlo con la salida de un comando externo capturándola directamente en Perl:

my @discos_llenos = grep { /(9[5-9]|100)%/ } `df -h`;
print @discos_llenos if @discos_llenos;

Aquí las comillas invertidas ejecutan df -h y devuelven su salida como texto, que grep (la función de Perl, no el comando de shell, aunque hacen algo conceptualmente parecido) filtra quedándose solo con las líneas donde el porcentaje de uso está entre el 95% y el 100% — un chivato rápido y sin dependencias de qué particiones están a punto de llenarse, el mismo tipo de aviso que, como se comentaba en un artículo reciente de observasistemas.com sobre monitorización clásica, sigue siendo imprescindible por muy sofisticado que sea el resto del stack de observabilidad.

Dónde Perl deja de ser la mejor opción

Sería deshonesto cerrar esta serie sin decir con claridad dónde Perl empieza a quedarse corto frente a alternativas modernas. En cuanto un script crece más allá de un puñado de líneas —necesita estructurarse en varios módulos, hablar con una API REST devolviendo JSON, o lo va a mantener un equipo entero durante años—, Python ofrece hoy una legibilidad y un ecosistema de librerías con los que Perl, en la práctica, no compite: instalar y gestionar dependencias de CPAN (el repositorio de módulos de Perl) es bastante más incómodo que un pip install moderno, y encontrar documentación o ejemplos recientes de librerías de Perl para tareas nuevas es cada vcez más raro. Perl tampoco brilla especialmente en programación orientada a objetos moderna, ni en concurrencia, terrenos donde nació después que otros lenguajes ya los habían resuelto mejor.

Pero para lo que se ha visto en este artículo —un filtrado rápido de un log gigante, una sustitución de texto sobre la marcha, una comprobación puntual del estado de un fichero de /proc sin montar un proyecto—, Perl sigue siendo, casi cuarenta años después de aquel anuncio de Larry Wall en 1987, una de las herramientas más rápidas de escribir y de ejecutar que tiene cualquier administrador de sistemas Linux a un perl -e de distancia.


Serie

  • Parte I: El script que revisa cada parche del kernel de Linux está escrito en Perl — de dónde viene Perl, por qué sigue en cualquier distribución Linux, y la sintaxis básica.
  • Parte II (este artículo): logs, procesos, one-liners y automatización básica del sistema.

Fuentes:

Deja una respuesta

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.