sed maneja transformación de texto orientada a líneas (sustitución, eliminación, inserción) mientras que awk destaca en la extracción, cálculo y agregación de datos por columnas. Canalízalos juntos y podrás procesar desde actualizaciones masivas de configuración hasta agregación de CSV y análisis de logs en one-liners.
"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.
Técnicas avanzadas
Agregación con arrays asociativos de awk
Los arrays asociativos de awk son poderosos para agrupar datos. Puedes replicar el GROUP BY de SQL en una sola línea.
# Tamaño total de respuesta por código de estado
awk '{status[$9]++; size[$9]+=$10} END {
for (s in status)
printf "%s: %d requests, %.2f MB\n", s, status[s], size[s]/1024/1024
}' access.log
Extracción de bloques específicos con direcciones de rango en sed
Usa direcciones de rango para extraer contenido entre dos patrones.
# Extraer bloques entre BEGIN y END
sed -n '/^BEGIN$/,/^END$/p' config.txt
# Extraer una definición de función (versión simple, sin coincidencia de llaves)
sed -n '/^function setup/,/^}/p' script.sh
Conversión de delimitadores de campo con awk OFS
Diferentes delimitadores de entrada y salida son comunes. Controla esto con OFS (Output Field Separator).
# Conversión TSV → CSV
awk 'BEGIN {FS="\t"; OFS=","} {$1=$1; print}' data.tsv > data.csv
# CSV → delimitado por pipes
awk -F',' 'BEGIN {OFS="|"} {$1=$1; print}' data.csv
$1=$1 es un truco que fuerza a awk a reconstruir el registro. Sin él, OFS no se aplica.
Espacio de retención (hold space) de sed
sed tiene dos búferes: el "espacio de patrones" (línea actual) y el "espacio de retención" (búfer temporal). Manipúlalos con h/H (guardar), g/G (restaurar) y x (intercambiar).
# Imprimir la línea antes de cada línea en blanco (obtener líneas al final de sección)
sed -n '/^$/!{h;d}; /^$/{x;p}' file.txt
Es una técnica avanzada, pero el espacio de retención puede ser la única solución para transformaciones de texto complejas.
FAQ
¿Cuándo usar sed vs awk?
Usa sed para reescritura orientada a líneas (sustitución, eliminación, inserción). Usa awk para extracción de columnas, cálculo y agregación. Si te preguntas "¿quiero transformar texto o extraer datos de él?" — la respuesta te dice qué herramienta usar.
¿Cuál es la diferencia entre el sed de macOS y el de Linux?
macOS viene con BSD sed, que maneja -i de forma diferente. GNU sed usa sed -i 's/...' para edición en su lugar, pero BSD sed requiere sed -i '' 's/...' con una extensión de respaldo vacía explícita. Instala GNU sed en macOS con brew install gnu-sed (disponible como gsed).
¿Cuál es la diferencia entre awk y gawk?
awk es el comando especificado por POSIX. gawk es la implementación GNU con extensiones como for...in para arrays asociativos, printf extendido y bloques BEGINFILE/ENDFILE. En Linux, awk es típicamente un enlace simbólico a gawk.
¿Puede sed manejar caracteres multi-byte (UTF-8)?
Sí, GNU sed procesa caracteres multi-byte según la configuración de tu locale. Con LC_ALL=es_ES.UTF-8 configurado, . (cualquier carácter) coincide con un carácter, no un byte. Esto funciona correctamente para caracteres acentuados, CJK y emoji.
¿Puede awk manejar archivos muy grandes (multi-GB)?
Sí. awk procesa la entrada como un flujo, línea por línea, sin cargar el archivo completo en memoria. Archivos de log de varios GB no son problema. Sin embargo, si acumulas muchas claves en arrays asociativos, el uso de memoria crece — en esos casos, considera sort | uniq -c como alternativa.
¿Debería usar sd o sed?
Para reemplazos simples (especialmente rutas y URLs), sd requiere menos escape y se lee más limpiamente. Para direccionamiento de líneas, manipulación del hold space y scripts complejos, sed es la única opción. Instala ambos y usa el que mejor se ajuste a la tarea.
¿Cómo previsualizo cambios de sed sin modificar el archivo?
Ejecuta sed 's/old/new/g' file.txt sin -i y el resultado va a stdout. Combina con diff: sed 's/old/new/g' file.txt | diff file.txt - para ver exactamente qué cambiaría.
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 herramientas relacionadas, consulta la guía de grep y ripgrep, guía de jq, herramientas CLI en Rust, y el mapa de herramientas CLI.