sed (stream editor) es un editor que nunca abre un archivo de forma interactiva. En su lugar, lee la entrada línea por línea, aplica las instrucciones que le das, y escribe el resultado en la salida estándar. Eso es todo. Su diseño intencional es procesamiento en flujo: stdin → transformación → stdout, encadenado con pipes o aplicado directamente sobre archivos.
El ciclo interno de sed es sencillo y vale la pena entenderlo: lee una línea al espacio de patrón (un búfer temporal), ejecuta todas las instrucciones en orden sobre ese búfer, imprime el resultado, lo descarta, y pasa a la siguiente línea. Este modelo explica por qué sed es tan rápido y por qué también tiene límites claros: no tiene noción global del archivo mientras procesa una línea. Si necesitas comparar la línea 3 con la línea 300, sed no es tu herramienta.
¿Cuándo usarlo? Para sustituciones de texto masivas, limpieza de archivos de configuración, eliminación de líneas que cumplen un patrón, o extracción de rangos de líneas. Es la navaja correcta cuando la tarea es “reemplaza esto por aquello en mil archivos”. Cuando la lógica crece —condiciones anidadas, operaciones sobre campos, acumulación de estado— awk o un script de Python hacen el trabajo con menos fricción.
Lo que rompe cuando lo usas mal: edición in-place sin entender las implicaciones, o asumir que s/patrón/reemplazo/ reemplaza todas las ocurrencias cuando sin el flag g solo reemplaza la primera de cada línea. También hay una trampa frecuente con el comportamiento de -i entre GNU sed (Linux) y BSD sed (macOS): en GNU sed -i 's/old/new/' archivo funciona directamente; en BSD necesitas sed -i '' 's/old/new/' archivo o explota con un error críptico. En Debian no te preocupa —tienes GNU sed— pero si mantienes scripts que corren en ambos entornos, el detalle importa.
# Archivo de configuración de ejemplo que vamos a manipular
cat > /tmp/servicio.conf << 'EOF'
# Configuración del servicio web
host=http://interno.ejemplo.com
puerto=8080
log_level=debug
ruta_datos=/usr/local/var/datos
ruta_logs=/usr/local/var/logs
# max_conexiones=100
timeout=30
EOF
# 1. Sustitución básica: http → https en todas las ocurrencias de cada línea
# Sin 'g', solo reemplazaría la primera ocurrencia por línea
sed 's/http/https/g' /tmp/servicio.conf
# 2. Delimitador alternativo: el patrón contiene '/', usamos '|' para evitar escapes
# sed 's/\/usr\/local/\/opt/g' funciona pero es ilegible
sed 's|/usr/local|/opt|g' /tmp/servicio.conf
# 3. Ambas transformaciones juntas con -e (múltiples expresiones)
sed -e 's/http/https/g' -e 's|/usr/local|/opt|g' /tmp/servicio.conf
# 4. Edición in-place: modifica el archivo directamente
# Sin -i, todo lo anterior solo imprimía en stdout sin tocar el archivo
sed -i 's/http/https/g' /tmp/servicio.conf
# Verificamos que el archivo cambió de verdad
grep 'http' /tmp/servicio.conf
# 5. Borrar líneas que coinciden con un patrón (comentarios y líneas vacías)
sed '/^#/d' /tmp/servicio.conf
# 6. Borrar un rango de líneas por número: elimina las líneas 1 a 3
sed '1,3d' /tmp/servicio.conf
# 7. Imprimir solo líneas específicas: -n suprime la impresión automática,
# 'p' imprime explícitamente. Sin -n, cada línea del rango saldría duplicada
sed -n '2,4p' /tmp/servicio.conf
# 8. ERE con -E: busca líneas que contengan puertos de 4 dígitos y los marca
# Sin -E, el + requería escape \+ en BRE
sed -n -E '/puerto=[0-9]{4}/p' /tmp/servicio.conf
# 9. Sustitución solo en líneas que coinciden con un patrón (dirección + comando)
# Cambia debug por info, pero únicamente en la línea que contiene 'log_level'
sed '/log_level/s/debug/info/' /tmp/servicio.conf
# Limpieza
rm /tmp/servicio.conf
El punto 1 ilustra la diferencia entre s/http/https/ y s/http/https/g: sin g, en una línea hipotética http://a.com y http://b.com, solo el primer http cambiaría. El flag g al final del comando de sustitución significa “aplica el reemplazo en toda la línea”, no “aplica en todo el archivo”.
El punto 2 muestra por qué los delimitadores alternativos existen. El delimitador por defecto es /, así que cuando el patrón o el reemplazo contienen barras, cada una necesita escape con \. Con rutas de sistema el resultado es ruido visual puro. Cualquier carácter que no aparezca en el patrón ni en el reemplazo puede ser delimitador: |, @, #, , —sed lee el carácter inmediatamente después de s como el delimitador.
En el punto 4, -i hace que sed sobreescriba el archivo original. GNU sed crea internamente un temporal, escribe allí, y lo mueve al nombre original. La consecuencia práctica: si el proceso se interrumpe a mitad, puedes quedarte con el archivo a medias. En scripts críticos conviene hacer una copia antes (cp archivo archivo.bak) o usar -i.bak que crea el backup automáticamente con esa extensión.
El punto 7 usa -n con p. Este par es inseparable: -n desactiva la impresión automática del espacio de patrón al final de cada ciclo, y p la activa explícitamente para las líneas que quieres. Sin -n, sed -n '2,4p' imprimiría las líneas 2-4 una vez; con -n olvidado, sed '2,4p' las imprimiría dos veces —una por el p y otra por la impresión automática.
El punto 9 muestra la dirección + comando: la sintaxis /patrón/comando limita la ejecución del comando a las líneas que coinciden con el patrón. Aquí, la sustitución s/debug/info/ solo se ejecuta en la línea que contiene log_level. Esto evita reemplazar accidentalmente la palabra debug en cualquier otro contexto del archivo. Es el mecanismo correcto para transformaciones condicionadas a contenido —sin necesidad de pipes ni lógica externa.
N° 51