"Necesito reemplazar valores masivamente en archivos de configuración." "Quiero extraer columnas específicas de un CSV y calcular totales." "Necesito eliminar ciertas líneas de un archivo de log."
Estos son escenarios clásicos de procesamiento de texto donde sed y awk brillan. Ambos son comandos filtro diseñados para pipelines, pero cada uno destaca en cosas distintas.
Este artículo te guía a través de los fundamentos de sed y awk, patrones prácticos y cómo combinarlos en flujos de trabajo potentes.
sed y awk: ¿Cuál es la diferencia?
Aquí tienes un resumen rápido.
| sed | awk | |
|---|---|---|
| Nombre completo | Stream Editor | Pattern scanning and processing language |
| Fortaleza | Transformación de texto orientada a líneas (sustitución, eliminación, inserción) | Procesamiento de datos orientado a columnas (extracción, cálculo, agregación) |
| Modelo mental | "Reescribir texto" | "Extraer datos del texto" |
| Uso típico | Actualizaciones de archivos de config, limpieza de logs | Agregación de CSV/TSV, análisis de logs de acceso |
Ambos son comandos filtro de pipeline conectados con |. sed destaca en transformación, awk destaca en extracción y cálculo. Mantén esta distinción en mente y siempre sabrás a cuál recurrir.
Fundamentos de sed
sed — el "editor de flujo" — lee texto línea por línea, aplica transformaciones y devuelve el resultado.
Sustitución
La operación más común es el comando s (sustituir).
# Reemplazar la primera coincidencia en cada línea
sed 's/old/new/' file.txt
# Reemplazar todas las coincidencias en cada línea (flag g)
sed 's/old/new/g' file.txt
# Editar el archivo en su lugar (opción -i)
sed -i 's/old/new/g' file.txt
Selección de líneas y rangos
# Sustituir solo en la línea 3
sed '3s/old/new/' file.txt
# Sustituir en las líneas 2 a 5
sed '2,5s/old/new/g' file.txt
# Sustituir solo en la última línea
sed '$s/old/new/' file.txt
Eliminación, inserción e impresión
# Eliminar líneas que coincidan con un patrón
sed '/pattern/d' file.txt
# Insertar una línea después de la coincidencia
sed '/pattern/a\nueva línea' file.txt
# Insertar una línea antes de la coincidencia
sed '/pattern/i\nueva línea' file.txt
# Imprimir solo un rango específico de líneas (-n suprime la salida por defecto)
sed -n '10,20p' file.txt
Operaciones múltiples y delimitadores personalizados
# Ejecutar múltiples sustituciones en una pasada
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
# Usar un delimitador alternativo (útil para rutas y URLs)
sed 's|/usr/local|/opt|g' config.txt
El delimitador puede ser cualquier carácter — |, #, @, etc. Esto elimina la necesidad de escapar / al trabajar con rutas de archivos.
sed en la práctica
Actualizaciones masivas de archivos de configuración
Un escenario común durante migraciones de servidor o despliegues.
# Actualizar DB_HOST en un archivo .env
NEW_HOST="db-prod.example.com"
sed -i "s/DB_HOST=.*/DB_HOST=${NEW_HOST}/" .env
# Comentar una línea
sed -i 's/^PermitRootLogin yes/# PermitRootLogin yes/' /etc/ssh/sshd_config
# Descomentar una línea
sed -i 's/^# *PermitRootLogin/PermitRootLogin/' /etc/ssh/sshd_config
Limpieza de archivos de log
# Eliminar líneas vacías
sed '/^$/d' file.txt
# Eliminar espacios al inicio y al final
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' file.txt
# Eliminar secuencias de escape ANSI (códigos de color)
sed 's/\x1b\[[0-9;]*m//g' colored-output.txt
Operaciones por lotes con find
# Reemplazar el año en todos los archivos .txt del proyecto
find . -name "*.txt" -exec sed -i 's/2025/2026/g' {} +
# Generar .env desde .env.example reemplazando valores
sed 's/DB_PASSWORD=changeme/DB_PASSWORD=s3cur3P@ss/' .env.example > .env
Fundamentos de awk
awk procesa texto a nivel de campo (columna). Cada línea se divide automáticamente por espacios en blanco, y los campos son accesibles como $1, $2, etc.
Ten en cuenta que gawk 5.4.0 cambió el motor de regex por defecto a MinRX, que es totalmente compatible con POSIX. Los patrones que dependan de extensiones regex específicas de GNU pueden comportarse de forma diferente. Para usar el motor antiguo, establece la variable de entorno GAWK_GNU_MATCHERS=1.
Extracción de columnas
# Imprimir la 1ª y 3ª columna
awk '{print $1, $3}' data.tsv
# Especificar un delimitador (para CSV)
awk -F',' '{print $1, $2}' data.csv
# Imprimir la línea completa ($0 es la línea entera)
awk '{print $0}' file.txt
Coincidencia de patrones y condiciones
# Imprimir solo líneas que contienen "error"
awk '/error/ {print $0}' logfile.txt
# Imprimir líneas donde la 3ª columna supera 100
awk '$3 > 100 {print $1, $3}' data.txt
# Combinar múltiples condiciones
awk '$3 > 100 && $2 == "active" {print $1, $3}' data.txt
Variables integradas
awk proporciona varias variables integradas útiles.
| Variable | Significado |
|---|---|
NR | Número de línea actual (Number of Records) |
NF | Número de campos en la línea actual (Number of Fields) |
FS | Separador de campos de entrada (Field Separator) |
OFS | Separador de campos de salida |
# Imprimir con números de línea
awk '{print NR": "$0}' file.txt
# Mostrar el conteo de campos de cada línea
awk '{print NR": "NF" campos"}' data.txt
# Imprimir el último campo
awk '{print $NF}' data.txt
Bloques BEGIN / END y agregación
# Añadir encabezado y pie
awk 'BEGIN {print "Nombre,Puntuación"} {print $1","$3} END {print "---fin---"}' data.txt
# Sumar la 2ª columna
awk '{sum += $2} END {print "Total:", sum}' sales.txt
# Calcular el promedio
awk '{sum += $2; count++} END {print "Promedio:", sum/count}' sales.txt
Salida formateada con printf
# Alinear a la izquierda 20 chars, a la derecha 10 chars con 2 decimales
awk '{printf "%-20s %10.2f\n", $1, $3}' data.txt
printf usa los mismos especificadores de formato que C. Es invaluable cuando necesitas salida tabular bien alineada.
awk en la práctica
Agregación de datos CSV/TSV
# Totales de ventas por categoría (usando arrays asociativos)
# Entrada: CSV con categoría,producto,cantidad
awk -F',' '{
sales[$1] += $3
}
END {
for (cat in sales)
printf "%-15s %10.0f\n", cat, sales[cat]
}' sales.csv
# Calcular máximo, mínimo y promedio en una pasada
awk 'BEGIN {max = -999999; min = 999999}
{
sum += $2
count++
if ($2 > max) max = $2
if ($2 < min) min = $2
}
END {
printf "Máx: %.2f Mín: %.2f Prom: %.2f\n", max, min, sum/count
}' data.txt
Análisis de logs de acceso
# Top 10 direcciones IP por número de peticiones
awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access.log | sort -rn | head -10
# Desglose de códigos de estado HTTP
# Formato CLF: IP - - [fecha] "método ruta proto" estado tamaño
awk '{print $9}' access.log | sort | uniq -c | sort -rn
Salida formateada
# Mostrar información de usuarios en formato tabla
awk -F':' 'BEGIN {
printf "%-20s %-6s %-6s %s\n", "USUARIO", "UID", "GID", "HOME"
printf "%-20s %-6s %-6s %s\n", "-------", "---", "---", "----"
}
$3 >= 1000 && $3 < 65534 {
printf "%-20s %-6s %-6s %s\n", $1, $3, $4, $6
}' /etc/passwd
Combinar sed y awk
sed y awk alcanzan su máximo potencial cuando se canalizan juntos. El patrón típico es sed para preprocesamiento (formateo, filtrado) seguido de awk para agregación.
# Eliminar la fila de encabezado de un CSV, luego sumar la 3ª columna
sed '1d' sales.csv | awk -F',' '{sum += $3} END {print "Total:", sum}'
# Extraer líneas ERROR de un log, luego mostrar solo la marca de tiempo y el mensaje
sed -n '/ERROR/p' app.log | awk '{print $1, $2, substr($0, index($0,$5))}'
# Extraer usuarios con bash de /etc/passwd y formatear la salida
grep '/bash$' /etc/passwd | awk -F':' '{printf "%-15s UID=%-6s %s\n", $1, $3, $6}'
# Contar errores de hoy en syslog por servicio
sed -n "/$(date '+%b %e')/p" /var/log/syslog | awk '/error|fail/ {count[$5]++} END {for (s in count) print count[s], s}' | sort -rn
Alternativa moderna: sd
sd es una alternativa a sed escrita en Rust. Comparado con la sintaxis s/old/new/g de sed, sd requiere menos escape y se lee más naturalmente.
Instalación
# En un entorno WSL, igual que Linux
cargo install sd
Uso básico
# Reemplazar vía stdin
echo "hello world" | sd 'world' 'earth'
# Editar un archivo en su lugar
sd 'old' 'new' file.txt
Comparación sed vs sd
| Operación | sed | sd |
|---|---|---|
| Reemplazo básico | sed 's/foo/bar/g' | sd 'foo' 'bar' |
| Reemplazo de rutas | sed 's|/usr/local|/opt|g' | sd '/usr/local' '/opt' |
| Grupos regex | sed 's/\(foo\)/[\1]/g' | sd '(foo)' '[$1]' |
| Edición en lugar | sed -i 's/foo/bar/g' file | sd 'foo' 'bar' file |
sd usa regex estilo PCRE por defecto, así que no hay necesidad de escapar \( \). Los reemplazos de rutas también funcionan sin cambiar el delimitador.
# Coincidencia multi-línea (v1.1.0+)
sd --across 'start\n.*\nend' 'replaced' file.txt
Si ya te sientes cómodo con sed, no hay necesidad de cambiar. Sin embargo, para one-liners donde el escape de regex se vuelve confuso, sd reduce significativamente la posibilidad de errores. Una regla práctica: usa sd para reemplazos simples, quédate con sed para direccionamiento de líneas y scripts complejos.
Conclusión
sed y awk son el dúo clásico del procesamiento de texto.
- sed — Sustitución, eliminación e inserción orientada a líneas. Perfecto para actualizaciones de configuración y limpieza de logs
- awk — Extracción, cálculo y agregación orientada a columnas. Ideal para procesamiento de CSV/TSV y análisis de logs de acceso
- sed + awk — Canalízalos juntos para preprocesamiento seguido de agregación. sed da forma, awk calcula
- sd — Una alternativa moderna para cuando la sintaxis de sed se vuelve difícil de manejar. Menos escape, one-liners más limpios
Ambas herramientas tienen casi 50 años de historia y están instaladas en cada sistema Linux. Empieza con el comando s de sed y el {print $1} de awk, luego construye tu repertorio de patrones desde ahí.
Para búsqueda de texto, combínalos con grep y ripgrep. Para procesamiento de JSON, consulta jq. Y para una visión general de todas las herramientas CLI, consulta el Kit de herramientas CLI.