Usos avanzados de sed: múltiples líneas, direcciones complejas y scripts reutilizables

DUGLAS MORENODUGLAS MORENO 👁 23

Introducción
¿Alguna vez te encontraste necesitando modificar archivos de texto de forma masiva, pero los comandos básicos de sed no alcanzaban porque necesitabas trabajar con varias líneas a la vez o aplicar patrones más complejos? Si trabajás con logs, archivos de configuración o cualquier tipo de dato textual, dominar los usos avanzados de sed te va a ahorrar horas de trabajo manual y te va a permitir crear pipelines de transformación potentes y reproducibles.

Este tutorial está dirigido a desarrolladores, administradores de sistemas y cualquiera que tenga que procesar texto en entornos Unix/Linux. Aprenderás a:

  • Usar direcciones complejas (rangos, patrones, pasos) para seleccionar exactamente las líneas que querés.
  • Trabajar con múltiples líneas mediante el espacio de patrón y el espacio de retención.
  • Aplicar los comandos más útiles como d (delete), s (sustitución) y y (transformación) en contextos avanzados.
  • Guardar y reutilizar scripts de sed en archivos para ejecutarlos de forma repetida.
  • Combinar sed con otras herramientas (grep, awk, find) para flujos de trabajo más poderosos.

Al final, vas a ver ejemplos concretos de transformación de texto, con la entrada y la salida esperada, para que puedas copiar y adaptar los comandos a tus propios casos.

1. Repaso rápido: cómo funciona sed

Antes de avanzar, recordemos el modelo básico de sed: lee línea por línea, coloca cada línea en el patrón space, aplica los comandos especificados y, por defecto, imprime el resultado. El hold space es un búfer adicional donde podés guardar temporalmente líneas para procesarlas más tarde.

2. Direcciones complejas: más allá de los números de línea

2.1 Rangos y pasos

Podés especificar un rango de líneas con la sintaxis inicio,fin. Por ejemplo, para aplicar un comando solo entre las líneas 10 y 20:

sed '10,20s/foo/bar/g' archivo.txt

Si querés aplicar un comando a cada quinta línea empezando desde la primera, usá el paso ~:

sed '1~5s/^/>>> /' archivo.txt   # agrega >>> al inicio de cada 5ª línea

2.2 Patrones como direcciones

En lugar de números, podés usar expresiones regulares para seleccionar líneas que coincidan con un patrón. Por ejemplo, borrar todas las líneas que contengan la palabra TODO:

sed '/TODO/d' archivo.txt

Combiná patrones y números: aplicar una sustitución solo en las líneas que empiecen con # y estén entre la línea 5 y el final:

sed '5,$/^#/s/# //' archivo.txt

2.3 Direcciones anidadas y múltiplos

Podés especificar varias direcciones separadas por coma para crear lógica AND, o usar {} para agrupar comandos bajo una misma dirección:

sed '/^ERROR/,/^$/ { s/ERROR/ALERTA/g; d }' archivo.log

Este ejemplo borra el bloque que comienza con una línea que tiene ERROR y termina con una línea vacía, pero antes de borrar reemplaza ERROR por ALERTA.

3. Trabajando con múltiples líneas

Por defecto, sed procesa una línea a la vez, lo que limita patrones que cruzan el salto de línea. Para superar esto, usamos el comando N (añadir próxima línea al patrón space) y D (borrar la primera línea del patrón space y volver a cargar la siguiente). También el comando G (añadir hold space al pattern space) y H (añadir pattern space al hold space) son fundamentales.

3.1 Unir líneas separadas por un guion

Supongamos que tenés un archivo donde algunas palabras están divididas por un guion y un salto de línea, y querés unirlas:

Entrada (texto.txt):

Este es un ejemplo-
de texto dividido-
en varias líneas.

Queremos obtener:

Este es un ejemplo de texto dividido en varias líneas.

Comando:

sed ':a; /-$/ { N; s/-
//; ba }' texto.txt

Explicación:

  • :a crea una etiqueta de salto.
  • /-$/ selecciona líneas que terminan con -.
  • N agrega la próxima línea al pattern space (incluye el
    ).
  • s/- // elimina el guion y el salto de línea.
  • ba salta de vuelta a la etiqueta :a si aún termina con -.

3.2 Eliminar bloques de comentario multilínea

Muchos lenguajes usan /* ... */ para comentarios de bloque. Queremos borrar todo lo que esté entre esos delimitadores, incluyendo el salto de línea.

Entrada (codigo.c):

/* Este es un
   comentario de bloque */
int main() {
    return 0;
}

Comando:

sed -e ':a' -e '/\\*\// { N; /\\*\//! ba; s/\\*[^*]*\\*//g; ta }' -e 'P; d' codigo.c

Este script es más complejo; lo desglosaremos en la sección de scripts.

3.3 Duplicar líneas que contienen una palabra clave

Queremos duplicar cada línea que contenga la palabra IMPORTANTE, dejando la original y agregando una copia justo después.

Entrada (notas.txt):

Reunión a las 10.
IMPORTANTE: revisar el informe.
Llamar al cliente.
IMPORTANTE: enviar el contrato.

Salida esperada:

Reunión a las 10.
IMPORTANTE: revisar el informe.
IMPORTANTE: revisar el informe.
Llamar al cliente.
IMPORTANTE: enviar el contrato.
IMPORTANTE: enviar el contrato.

Comando:

sed '/IMPORTANTE/ { p; }' notas.txt

El comando p imprime el pattern space; como sed ya imprime automáticamente cada línea, al agregar p estamos imprimiendo una segunda copia.

3.4 Intercambio de dos columnas usando hold space

Imaginemos un archivo CSV sencillo con dos columnas separados por coma y queremos invertir el orden.

Entrada (datos.csv):

nombre,edad
Ana,30
Luis,25
Marta,28

Salida esperada:

edad,nombre
30,Ana
25,Luis
28,Marta

Comando:

sed '1s/\([^,]*\),\([^,]*\)/\2,\1/; t; :a; N; s/\([^
]*\)
\([^,]*\),\([^,]*\)/\2,\3
\1/; ta; P; d' datos.csv

Esto es avanzado; mejor usar un script.

4. Comandos esenciales en profundidad

4.1 d – borrar líneas

Además de borrar por patrón, podés usar d dentro de un bloque para borrar todo lo que haya acumulado en el pattern space luego de ciertas operaciones.

Ejemplo: borrar todo el contenido entre dos marcadores START y END, inclusive.

sed '/START/,/END/d' archivo.txt

Si querés borrar solo lo que está entre los marcadores, dejando los marcadores:

sed '/START/,/END/{/START/b; /END/b; d}' archivo.txt

Aquí b hace un salto (branch) al final del script cuando se encuentra el marcador, evitando que d actúe sobre él.

4.2 s – sustitución con flags avanzados

Además del global g, podés usar:

  • en la parte de reemplazo para insertar un salto de línea (requiere que el pattern space tenga más de una línea).
  • \L y \U para convertir a minúsculas o mayúsculas la porción reemplazada.
  • & para referirse al texto completo que coincidió con el patrón.

Ejemplo: envolver cada número entre corchetes y convertirlo a hexadecimal (solo como demostración de &).

sed 's/[0-9]\+/[&]/g' archivo.txt

Para cambiar a mayúsculas la primera letra de cada palabra:

sed 's/\b\([a-z]\)/\U\1/g' archivo.txt

4.3 y – transformación de caracteres

El comando y funciona como el operador tr: reemplaza cada carácter de la primera lista por el correspondiente en la segunda.

Ejemplo: pasar todo el texto a modo "leet speak" básico (a→4, e→3, i→1, o→0, s→5).

sed 'y/aeios/43105/' archivo.txt

5. Scripts de sed en archivos

Cuando los comandos se vuelven largos o necesitás reutilizarlos, es mejor guardarlos en un archivo de script y ejecutarlos con -f.

5.1 Estructura básica de un script

Un archivo de script contiene una línea por comando (o bloque). Los comentarios empiezan con #.

Ejemplo de script limpiar.sed:

# Eliminar líneas en blanco
/^$/d

# Reemplazar múltiples espacios por uno solo
s/  */ /g

# Quitar comentarios de línea que empiecen con #
/^#/d

Uso:

sed -f limpiar.sed entrada.txt > salida.txt

5.2 Script para unir líneas divididas por guion (reutilizable)

Guardemos el script anterior en join-hyphen.sed:

:a
/-$/ {
    N
    s/-
//
    ba
}

Uso:

sed -f join-hyphen.sed fragmento.txt

5.3 Script avanzado: borrar comentarios de bloque C

Este script maneja comentarios /* ... */ que pueden abarcar varias líneas.

Archivo rm-c-comments.sed:

# Etiqueta de inicio
:start
# Si encontramos /*
/\*\/ {
    # Traemos líneas hasta encontrar */
    :loop
    N
    /\*\//! b loop
    # Ahora tenemos el comentario completo en pattern space
    s/\*[^*]*\*//g
    # Si después de borrar queda algo que aún comienza con /*, repetimos
    /\*\/ b start
}

Uso:

sed -f rm-c-comments.sed codigo.c > codigo_limpio.c

5.4 Debugging de scripts

Para ver qué está haciendo sed en cada paso, usá el comando l (lista) que muestra el contenido del pattern space con caracteres no imprimibles escapados.

sed -n 'l' script.sed archivo.txt

O bien usar el debug de GNU sed con --debug.

6. Ejemplos prácticos de transformación de texto

A continuación, varios casos de uso reales con entrada, comando y salida esperada.

6.1 Formatear un archivo de log de Apache

Supongamos un log donde cada línea tiene:

[10/Oct/2023:13:55:36 +0000] GET /index.html HTTP/1.1 200 1024

Queremos extraer solo la ruta y el código de estado, separados por una tabulación.

Entrada (access.log):

[10/Oct/2023:13:55:36 +0000] GET /index.html HTTP/1.1 200 1024
[10/Oct/2023:13:56:01 +0000] POST /api/data HTTP/1.1 500 0
[10/Oct/2023:13:57:12 +0000] GET /static/style.css HTTP/1.1 304 0

Comando:

sed -E 's/.* [A-Z]+ ([^ ]+) HTTP/[^ ]+ ([0-9]{3}) .*/\1	\2/' access.log

Salida esperada:

/index.html	200
/api/data	500
/static/style.css	304

6.2 Normalizar nombres de archivo en un listado

Tenés un listado de archivos con mayúsculas y minúsculas mezcladas, y querés que todo sea minúsculo y los espacios se reemplacen por guiones bajos.

Entrada (lista.txt):

Informe Final.pdf
Foto de Vacaciones.JPG
datos de prueba.png

Comando:

sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/; s/ /_/g' lista.txt

Salida esperada:

informe_final.pdf
foto_de_vacaciones.jpg
datos_de_prueba.png

6.3 Extraer bloques de código Markdown

Querés extraer únicamente los bloques de código delimitados por triple backticks (```) de un archivo Markdown, incluyendo los delimitadores.

Entrada (readme.md):

Este es un ejemplo.

```bash
echo 'Hola Mundo'

Algunos comentarios.

def suma(a, b):
    return a + b

Comando:
```bash
sed -n '/^```/,/^```/ p' readme.md

Salida esperada:

```bash
echo 'Hola Mundo'
def suma(a, b):
    return a + b

### 6.4 Convertir fechas de formato europeo a ISO
Tenés fechas en formato dd/mm/aaaa y querés aaaa-mm-dd.

Entrada (fechas.txt):

01/02/2023
15/08/2022
31/12/2021


Comando:
```bash
sed -E 's#([0-9]{2})/([0-9]{2})/([0-9]{4})#\3-\2-\1#' fechas.txt

Salida esperada:

2023-02-01
2022-08-15
2021-12-31

6.5 Anonimizar direcciones IP en un archivo de configuración

Querés reemplazar cualquier dirección IPv4 por X.X.X.X.

Entrada (config.ini):

listen = 192.168.1.10:8080
allow = 10.0.0.0/24

Comando:

sed -E 's/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/X.X.X.X/g' config.ini

Salida esperada:

listen = X.X.X.X:8080
allow = X.X.X.X/24

7. Buenas prácticas y errores comunes

7.1 Siempre probar con -n y p o con una copia de seguridad

Antes de ejecutar un sed que modifica archivos en sitio (-i), hacé una prueba en pantalla o con una copia de seguridad:

sed -i.bak 's/foo/bar/g' archivo.txt

7.2 Tener cuidado con los delimitadores en s

Si el patrón contiene el delimitador que elegiste (usualmente /), cambiá a otro carácter para evitar escape innecesario. Por ejemplo, usando |:

sed 's|/ruta/antigua|/ruta/nueva|g' rutas.txt

7.3 Recordar que `

en la parte de reemplazo solo funciona si hay más de una línea en el pattern space Si intentás insertar un salto de línea con
en una sustitución simple sobre una línea única, no va a funcionar. UsáGoN` para crear líneas múltiples antes.

7.4 Evitar la codicia excesiva con .*

En expresiones regulares, .* es codicioso y puede consumir más de lo esperado. Usá [^]]* para evitar consumir corchetes de cierre.

Ejemplo: extraer texto entre corchetes sin consumir corchetes internos:

sed -n 's/\[([^]]*)\]/\1/p' texto.txt

7.5 Comentá tus scripts

Cuando guardes scripts en archivos, usá # para explicar cada bloque. Esto facilita el mantenimiento y la reutilización por otros miembros del equipo.

7.6 Usá archivos de prueba

Mantené un pequeño archivo de muestra con los casos edge (líneas vacías, solo delimitadores, etc.) y probá tus scripts allí antes de aplicarlos a producción.

8. Conclusión

Dominar los usos avanzados de sed te brinda una herramienta ligera pero increíblemente poderosa para manipular texto directamente desde la línea de comandos. Has visto cómo:

  • Seleccionar líneas con direcciones complejas (rangos, patrones, pasos).
  • Trabajar con múltiples líneas usando N, G, H y etiquetas de salto.
  • Aplicar comandos como d, s y y en contextos avanzados.
  • Guardar y reutilizar scripts en archivos para tareas repetitivas.
  • Combinar sed con otras utilidades para construir pipelines de procesamiento de datos.

Con estos conocimientos, podés automatizar tareas que antes requerían scripts en Python o Perl, reduciendo dependencias y aumentando la velocidad de ejecución. Te animo a experimentar con los ejemplos proporcionados, adaptarlos a tus propios archivos y crear tu biblioteca personal de scripts sed. Cada vez que te enfrentes a un desafío de transformación de texto, recordá que sed probablemente tenga una solución elegante y eficiente.

Próximos pasos:

  • Explorar la variante gsed (GNU sed) para acceder a flags como -z (tratar el archivo completo como una sola línea) y expresiones regulares Perl-compatibles.
  • Integrar sed en tus pipelines de CI/CD para validar y formatear archivos de configuración automáticamente.
  • Combinar sed con awk para situaciones donde necesites hacer cálculos además de sustituciones.

¡Manos al teclado y que el flujo de texto esté siempre a tu favor!

Comentarios (0)

Sé el primero en comentar.

Dejá tu comentario