Comandos grep, awk, sed y cut

Herramientas poderosas para procesamiento y manipulación avanzada de texto

Módulo 5 ⏱️ 40-45 min 🔍 Procesamiento ✂️ Texto 📊 Intermedio

Introducción a las Herramientas de Texto

Unix/Linux ofrece un conjunto poderoso de herramientas especializadas en el procesamiento de texto. Estas herramientas, siguiendo la filosofía Unix de "hacer una cosa y hacerla bien", pueden combinarse para realizar tareas complejas de manipulación de datos.

Comparación de Herramientas

grep

Búsqueda
Encuentra patrones en texto

cut

Extracción
Corta columnas de texto

sed

Edición
Editor de flujo no interactivo

awk

Procesamiento
Lenguaje de programación

grep - Búsqueda de Patrones

grep (Global Regular Expression Print) es una herramienta fundamental para buscar texto que coincida con patrones específicos en archivos o entrada estándar.

Sintaxis Básica

Sintaxis de grep Copiar
# Sintaxis básica
grep [opciones] patrón [archivo...]

# Ejemplos básicos
grep "error" archivo.log           # Buscar "error" en archivo
grep -i "ERROR" archivo.log        # Búsqueda insensible a mayúsculas
grep -n "warning" archivo.log      # Mostrar números de línea
grep -v "debug" archivo.log        # Líneas que NO contienen "debug"
grep -c "success" archivo.log      # Contar coincidencias

Opciones Importantes

# Búsqueda recursiva en directorios
$ grep -r "function" /home/user/scripts/
/home/user/scripts/backup.sh:function create_backup() {
/home/user/scripts/utils.sh:function log_message() {

# Mostrar contexto (líneas antes y después)
$ grep -A 3 -B 2 "ERROR" app.log
2024-01-15 10:23:45 INFO Starting application
2024-01-15 10:23:46 WARN Configuration file missing
2024-01-15 10:23:47 ERROR Failed to connect to database
2024-01-15 10:23:48 ERROR Retrying connection...
2024-01-15 10:23:49 INFO Connection established

# Buscar múltiples patrones
$ grep -E "(error|warning|critical)" system.log
2024-01-15 10:15:22 WARNING High memory usage
2024-01-15 10:16:33 ERROR Database timeout
2024-01-15 10:17:44 CRITICAL System overload
Expresiones Regulares con grep

grep soporta diferentes tipos de expresiones regulares:

  • grep: Expresiones regulares básicas (BRE)
  • grep -E / egrep: Expresiones regulares extendidas (ERE)
  • grep -F / fgrep: Cadenas fijas (sin regex)
  • grep -P: Expresiones regulares compatibles con Perl

cut - Extracción de Columnas

cut extrae secciones específicas de cada línea de texto, siendo ideal para procesar datos estructurados como CSV o archivos delimitados.

Modos de Operación

Sintaxis de cut Copiar
# Por caracteres
cut -c 1-5 archivo.txt             # Caracteres 1 al 5
cut -c 1,3,5 archivo.txt           # Caracteres 1, 3 y 5
cut -c 5- archivo.txt              # Desde el carácter 5 al final

# Por campos (delimitados)
cut -d ',' -f 1,3 datos.csv        # Campos 1 y 3, delimitador coma
cut -d ':' -f 1 /etc/passwd        # Primer campo (usuario) de passwd
cut -d ' ' -f 2-4 archivo.txt      # Campos 2 al 4, delimitador espacio

# Por bytes
cut -b 1-10 archivo.txt            # Primeros 10 bytes

Ejemplos Prácticos

# Extraer usuarios del sistema
$ cut -d ':' -f 1 /etc/passwd | head -5
root
daemon
bin
sys
sync

# Procesar archivo CSV
$ cat ventas.csv
Fecha,Vendedor,Producto,Cantidad,Precio
2024-01-15,Juan,Laptop,2,1200.00
2024-01-15,Maria,Mouse,5,25.50

$ cut -d ',' -f 2,4 ventas.csv
Vendedor,Cantidad
Juan,2
Maria,5

# Extraer direcciones IP de logs
$ cut -d ' ' -f 1 access.log | head -3
192.168.1.100
10.0.0.15
172.16.0.50
Limitaciones de cut

cut no puede manejar delimitadores de longitud variable (como múltiples espacios). Para esto, es mejor usar awk.

sed - Editor de Flujo

sed (Stream Editor) es un editor no interactivo que puede realizar transformaciones de texto complejas. Es especialmente útil para sustituciones, eliminaciones e inserciones automatizadas.

Comandos Fundamentales

Comandos sed básicos Copiar
# Sustitución (s)
sed 's/viejo/nuevo/' archivo.txt              # Primera ocurrencia por línea
sed 's/viejo/nuevo/g' archivo.txt             # Todas las ocurrencias
sed 's/viejo/nuevo/2' archivo.txt             # Segunda ocurrencia por línea

# Eliminación (d)
sed '3d' archivo.txt                          # Eliminar línea 3
sed '/patrón/d' archivo.txt                   # Eliminar líneas con patrón
sed '1,5d' archivo.txt                        # Eliminar líneas 1-5

# Inserción y adición
sed '3i\Nueva línea' archivo.txt              # Insertar antes de línea 3
sed '3a\Nueva línea' archivo.txt              # Añadir después de línea 3

# Imprimir líneas específicas
sed -n '1,10p' archivo.txt                    # Imprimir líneas 1-10
sed -n '/patrón/p' archivo.txt                # Imprimir líneas con patrón

Ejemplos Avanzados

# Reemplazar múltiples patrones
$ echo "Hola mundo" | sed 's/Hola/Hello/; s/mundo/world/'
Hello world

# Cambiar formato de fecha
$ echo "2024-01-15" | sed 's/\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\)/\3\/\2\/\1/'
15/01/2024

# Eliminar líneas vacías
$ sed '/^$/d' archivo.txt

# Numerar líneas no vacías
$ sed '/./=' archivo.txt | sed 'N; s/\n/\t/'

# Convertir a mayúsculas (donde esté disponible)
$ echo "texto en minúsculas" | sed 's/.*/\U&/'
TEXTO EN MINÚSCULAS
Modificación In-Situ

Con la opción -i, sed puede modificar archivos directamente:

sed -i 's/viejo/nuevo/g' archivo.txt          # Modifica el archivo
sed -i.bak 's/viejo/nuevo/g' archivo.txt     # Crea respaldo .bak

awk - Procesamiento Avanzado

awk es un lenguaje de programación completo diseñado para el procesamiento de texto. Divide automáticamente cada línea en campos y permite realizar cálculos complejos.

Estructura de awk

Estructura de awk Copiar
# Estructura básica
awk 'patrón { acción }' archivo

# Variables automáticas importantes
# $0 = línea completa
# $1, $2, $3... = campos individuales
# NF = número de campos en la línea actual
# NR = número de línea actual
# FS = separador de campos (por defecto: espacio/tab)

# Ejemplos básicos
awk '{ print $1 }' archivo.txt               # Imprimir primer campo
awk '{ print NF, $0 }' archivo.txt           # Número de campos y línea
awk 'NR==5' archivo.txt                      # Imprimir línea 5
awk 'NF > 3' archivo.txt                     # Líneas con más de 3 campos

Operaciones Comunes

# Sumar una columna
$ awk '{ sum += $3 } END { print "Total:", sum }' ventas.txt
Total: 15750.00

# Calcular promedio
$ awk '{ sum += $2; count++ } END { print "Promedio:", sum/count }' datos.txt
Promedio: 87.5

# Formatear salida
$ awk '{ printf "%-10s %8.2f\n", $1, $2 }' productos.txt
Laptop       1200.00
Mouse          25.50
Teclado       150.00

# Procesar CSV con separador personalizado
$ awk -F ',' '{ print $2, $4 }' datos.csv
Juan 2
Maria 5
Carlos 3

# Contar ocurrencias
$ awk '{ count[$1]++ } END { for (i in count) print i, count[i] }' access.log
192.168.1.100 45
10.0.0.15 23
172.16.0.50 18

Scripts awk Avanzados

Script awk para análisis de logs Copiar
#!/usr/bin/awk -f
# Análisis de logs de Apache/Nginx

BEGIN {
    print "=== Análisis de Log ===="
    print "IP\t\tRequests\tBytes"
    print "--------------------------------"
}

{
    # Supone formato: IP - - [fecha] "request" status bytes
    ip = $1
    bytes = $10
    
    # Acumular estadísticas
    requests[ip]++
    total_bytes[ip] += bytes
    grand_total += bytes
}

END {
    # Imprimir estadísticas por IP
    for (ip in requests) {
        printf "%-15s %8d %12d\n", ip, requests[ip], total_bytes[ip]
    }
    
    print "--------------------------------"
    printf "Total bytes transferidos: %d\n", grand_total
    printf "Número total de IPs: %d\n", length(requests)
}

Combinando Herramientas

El verdadero poder de estas herramientas surge cuando se combinan usando pipes y redirecciones para crear pipelines de procesamiento complejos.

# Pipeline complejo: análisis de log de servidor web
$ grep "ERROR" /var/log/apache2/error.log | \
  cut -d' ' -f1-3 | \
  sort | \
  uniq -c | \
  sort -nr | \
  head -10
     42 [Mon Oct 15
     38 [Tue Oct 16
     35 [Wed Oct 17

# Extraer y procesar datos de un CSV
$ cat ventas.csv | \
  grep -v "Fecha" | \
  cut -d',' -f4,5 | \
  awk -F',' '{ total += $1 * $2 } END { print "Ingresos totales: $" total }'
Ingresos totales: $3876.50

# Análisis de uso de memoria por proceso
$ ps aux | \
  awk 'NR>1 { mem[$11] += $6 } END { for (cmd in mem) printf "%-20s %8.2f MB\n", cmd, mem[cmd]/1024 }' | \
  sort -k2 -nr | \
  head -5
firefox             1247.83 MB
chrome              987.45 MB
java                654.23 MB

# Encontrar archivos grandes y organizarlos
$ find /var/log -type f -name "*.log" | \
  xargs ls -la | \
  awk '{ print $5, $9 }' | \
  sort -nr | \
  head -10 | \
  awk '{ printf "%8.2f MB  %s\n", $1/1024/1024, $2 }'
   45.67 MB  /var/log/syslog
   23.45 MB  /var/log/auth.log
   18.92 MB  /var/log/apache2/access.log
Pipeline Optimization Tips
  • Usa grep primero para filtrar datos antes de procesamiento pesado
  • cut es más rápido que awk para extracciones simples
  • sed es eficiente para sustituciones simples en archivos grandes
  • awk es ideal cuando necesitas cálculos o lógica compleja
  • Usa sort -u en lugar de sort | uniq cuando sea posible

Ejercicios Prácticos

Ejercicio 1: Análisis de Log

Crea un script que analice un log de servidor web:

Ejercicio log analyzer Copiar
#!/bin/bash
# Crear datos de prueba
cat > access.log << EOF
192.168.1.100 - - [15/Oct/2024:10:15:22] "GET /index.html" 200 1024
10.0.0.15 - - [15/Oct/2024:10:16:33] "POST /login" 404 512
192.168.1.100 - - [15/Oct/2024:10:17:44] "GET /images/logo.png" 200 2048
172.16.0.50 - - [15/Oct/2024:10:18:55] "GET /about.html" 500 256
192.168.1.100 - - [15/Oct/2024:10:19:11] "GET /contact" 200 1536
EOF

# 1. Top 5 IPs por número de requests
echo "=== Top 5 IPs por requests ==="
awk '{ print $1 }' access.log | sort | uniq -c | sort -nr | head -5

# 2. Códigos de respuesta más comunes
echo -e "\n=== Códigos de respuesta ==="
awk '{ print $9 }' access.log | sort | uniq -c | sort -nr

# 3. Total de bytes transferidos por IP
echo -e "\n=== Bytes por IP ==="
awk '{ bytes[$1] += $10 } END { 
    for (ip in bytes) printf "%-15s %8d bytes\n", ip, bytes[ip] 
}' access.log | sort -k2 -nr
Ejercicio 2: Procesador de CSV

Procesa un archivo CSV de ventas:

Procesador CSV Copiar
#!/bin/bash
# Crear datos de prueba
cat > ventas.csv << EOF
Fecha,Vendedor,Producto,Cantidad,Precio_Unitario,Ciudad
2024-01-15,Juan,Laptop,2,1200.00,Madrid
2024-01-15,Maria,Mouse,5,25.50,Barcelona
2024-01-16,Carlos,Teclado,3,150.00,Valencia
2024-01-16,Ana,Monitor,1,300.00,Madrid
2024-01-17,Juan,Laptop,1,1200.00,Sevilla
EOF

echo "=== Análisis de Ventas ==="

# 1. Ventas totales por vendedor
echo "Ventas por vendedor:"
tail -n +2 ventas.csv | \
awk -F',' '{ 
    ventas[$2] += $4 * $5 
} END { 
    for (vendedor in ventas) 
        printf "%-10s: €%.2f\n", vendedor, ventas[vendedor] 
}' | sort -k2 -nr

# 2. Producto más vendido
echo -e "\nProductos más vendidos:"
tail -n +2 ventas.csv | \
cut -d',' -f3,4 | \
awk -F',' '{ productos[$1] += $2 } END { 
    for (producto in productos) 
        printf "%-10s: %d unidades\n", producto, productos[producto] 
}' | sort -k2 -nr

# 3. Ventas por ciudad
echo -e "\nVentas por ciudad:"
tail -n +2 ventas.csv | \
awk -F',' '{ ciudades[$6] += $4 * $5 } END { 
    for (ciudad in ciudades) 
        printf "%-12s: €%.2f\n", ciudad, ciudades[ciudad] 
}' | sort -k2 -nr