32blogby Studio Mitsu

Guía práctica de sed y awk: el dúo clásico del procesamiento de texto

Domina sed (sustitución, eliminación, inserción) y awk (extracción de columnas, agregación) con ejemplos prácticos.

by omitsu13 min read
Contenido

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.

sedawk
Nombre completoStream EditorPattern scanning and processing language
FortalezaTransformació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ípicoActualizaciones de archivos de config, limpieza de logsAgregació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).

bash
# 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

bash
# 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

bash
# 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

bash
# 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.

bash
# 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

bash
# 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

bash
# 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

bash
# 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

bash
# 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.

VariableSignificado
NRNúmero de línea actual (Number of Records)
NFNúmero de campos en la línea actual (Number of Fields)
FSSeparador de campos de entrada (Field Separator)
OFSSeparador de campos de salida
bash
# 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

bash
# 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

bash
# 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

bash
# 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
bash
# 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

bash
# 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
bash
# 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

bash
# 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.

bash
# 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}'
bash
# 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))}'
bash
# 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}'
bash
# 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

bash
# En un entorno WSL, igual que Linux
cargo install sd

Uso básico

bash
# 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ónsedsd
Reemplazo básicosed 's/foo/bar/g'sd 'foo' 'bar'
Reemplazo de rutassed 's|/usr/local|/opt|g'sd '/usr/local' '/opt'
Grupos regexsed 's/\(foo\)/[\1]/g'sd '(foo)' '[$1]'
Edición en lugarsed -i 's/foo/bar/g' filesd '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.

bash
# 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.

bash
# 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.

bash
# 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).

bash
# 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).

bash
# 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.