Sed Buscar y Reemplazar: Domina las Técnicas Avanzadas
Domina buscar y reemplazar con sed con ejemplos prácticos: el comando de sustitución (s), patrones regex, edición in-place y consejos de portabilidad GNU vs BSD para 2026.
Actualizado Publicado 30 min de lectura

¿Necesitas buscar y reemplazar texto en archivos sin abrir un editor? El comando s de sed maneja la búsqueda y el reemplazo en una sola línea. Útil para actualizaciones de configuración, limpieza de datos o ediciones por lotes dentro de los flujos de trabajo de los comandos esenciales de Linux.
¿Qué es sed?
sed (Stream Editor) procesa texto línea a línea sin cargar el archivo completo en memoria. Útil para:
- Automatización y scripts
- Archivos grandes
- Hacer piping con otras herramientas Unix
- Procesamiento por lotes
Esta guía se centra en GNU sed (el predeterminado en Linux) pero cubre las diferencias de macOS/BSD y Alpine/busybox en una sección de portabilidad dedicada.
Otras guías de sed:
Sintaxis básica
El comando de sustitución (s)
sed 's/old/new/' file.txt # Replace first occurrence per line
sed 's/old/new/g' file.txt # Replace all occurrences (global)
sed 's/old/new/I' file.txt # Ignore case (use capital I, portable)Usa I mayúscula, no i minúscula
La i minúscula funciona en GNU sed pero es ambigua con el comando insert y falla en macOS/BSD. La I mayúscula es la forma portable. Funciona en GNU sed y en macOS Big Sur (11.0) y posteriores.
Delimitadores
Usa delimitadores diferentes cuando tu patrón contiene barras:
sed 's|/old/path|/new/path|g' config.txt
sed 's#http://old#https://new#g' urls.txtOpciones clave
| Opción | Función | Ejemplo |
|---|---|---|
-i |
Edita archivos in-place | sed -i 's/old/new/g' file.txt |
-i.bak |
Edición in-place con backup | sed -i.bak 's/old/new/g' file.txt |
-n |
Suprime la salida por defecto | sed -n 's/old/new/p' file.txt |
-e |
Comandos múltiples | sed -e 's/old/new/' -e 's/foo/bar/' file.txt |
-n + -i trunca archivos
Nunca combines -n y -i en la misma invocación de sed. sed -ni 's/foo/bar/' FILE trunca FILE a cero bytes silenciosamente. El flag -n suprime la salida, y -i escribe esa salida (vacía) de vuelta al archivo. Usa -i.bak solo para una edición in-place segura.
Importante: Prueba sin -i primero. Sed escribe a stdout por defecto.
Ejemplos comunes
Archivos de configuración:
sed 's/localhost/production-server/g' config.ini
sed 's/port=8080/port=80/g' server.confRefactorización de código:
sed 's/oldFunction/newFunction/g' script.js
sed 's/var /let /g' legacy.jsLimpieza de datos:
sed 's/,/;/g' data.csv # Change delimiter
sed 's/ / /g' document.txt # Fix double spaces
sed 's/\t/ /g' file.txt # Tabs to spaces (GNU-only, see portability section)Operaciones con archivos
sed 's/old/new/g' file.txt > newfile.txt # Save to new file
sed -i 's/old/new/g' file.txt # Edit in place
sed -i.bak 's/old/new/g' file.txt # Edit with backupReemplazos múltiples
sed -e 's/old1/new1/g' -e 's/old2/new2/g' file.txt
sed 's/old1/new1/g; s/old2/new2/g' file.txtConsejos de seguridad
- Prueba sin
-iprimero - Usa
-i.bakpara backups - Verifica con
diff original.txt modified.txt - Nunca combines
-ncon-i(trunca el archivo, mira la advertencia de arriba)
GNU vs BSD vs busybox: sed portable
Tu portátil de desarrollo probablemente corre macOS (BSD sed), tu VPS de producción corre Linux (GNU sed), y tu CI/CD podría correr contenedores Alpine (busybox sed). Un script de sed que funciona en uno puede fallar silenciosamente en otro. Esta sección cubre las diferencias que de verdad rompen cosas.
¿Qué sed estás usando?
Ejecuta sed --version en Linux (GNU sed) o sed --version 2>&1 | head -1 en macOS (BSD sed). En Alpine: sed --help 2>&1 | head -1. Saber qué sabor tienes es el primer paso para escribir scripts portables.
El flag -i
Esta es la ruptura de portabilidad #1 con la que la gente tropieza.
GNU y busybox aceptan un sufijo pegado o -i a secas:
sed -i 's/foo/bar/g' file.txt # GNU/busybox: works
sed -i.bak 's/foo/bar/g' file.txt # GNU/busybox: works, creates backupBSD/macOS requiere el sufijo como argumento separado:
sed -i '' 's/foo/bar/g' file.txt # macOS: no backup
sed -i '.bak' 's/foo/bar/g' file.txt # macOS: with backupCorrer sed -i 's/foo/bar/g' file.txt en macOS se traga el script como sufijo y da el error “invalid command code.”
Patrón universal seguro (funciona en todas partes):
sed -i.bak 's/foo/bar/' config.conf && rm config.conf.bakExtensiones regex
Estas extensiones GNU no hacen nada silenciosamente o se comportan mal en otros sed:
| Característica | GNU sed | BSD/macOS | busybox | Alternativa portable |
|---|---|---|---|---|
\b (límite de palabra) |
Sí | No (no-op silencioso) | No (no-op silencioso) | Ancla con caracteres circundantes |
\w, \s |
Sí | No | No | [[:alnum:]], [[:space:]] |
\<, \> |
Sí | No | No | [[:<:]]/[[:>:]] solo en BSD |
\+ en BRE |
Sí | No (+ literal) |
No | Usa -E y + |
\t en regex |
Sí | No (t literal) |
No | Usa tab literal o [[:space:]] |
\d |
No | No | No | Usa [0-9] o [[:digit:]] |
\b es la trampa más desagradable. Silenciosamente no coincide con nada, así que tu sustitución parece funcionar pero no hace nada. Sin error, sin advertencia.
Flags y opciones
| Característica | GNU sed | macOS/BSD | busybox |
|---|---|---|---|
I (insensible a mayúsculas) |
Sí | Sí (Big Sur 11.0+) | Parcial |
-E (regex extendida) |
Sí | Sí (10.13+) | Mayormente |
--debug |
Sí (4.6+) | No | No |
--sandbox |
Sí | No | No |
-z (delimitado por nulo) |
Sí | No | No |
Wrapper universal de in-place para scripts
Si escribes scripts de sed que corren en múltiples plataformas (CI/CD, dotfiles compartidos, comandos de Docker en Alpine), usa este patrón:
# Works on GNU, macOS, and Alpine busybox
sed -i.bak 's/foo/bar/' config.conf && rm config.conf.bakPara pipelines de CI, envuélvelo en una función:
sed_inplace() {
sed -i.bak "$@" && rm -f "${@: -1}.bak"
}Coincidencia avanzada de patrones con expresiones regulares
Las expresiones regulares son donde sed pasa de simple buscar-y-reemplazar a procesamiento de texto real. Los patrones de abajo cubren lo que de verdad vas a usar.
Elementos básicos de expresiones regulares
Carácter comodín (.):
sed 's/t.st/test/g' filename # Matches "test", "tast", "t3st", etc.
sed 's/c.t/cat/g' pets.txt # Matches "cat", "cut", "cot", etc.Clases de caracteres:
sed 's/[aeiou]/X/g' filename # Replace any vowel with X
sed 's/[0-9]/N/g' filename # Replace any digit with N
sed 's/[A-Z]/L/g' filename # Replace uppercase letters with LClases de caracteres predefinidas:
sed 's/[[:digit:]]/N/g' filename # Replace digits (same as [0-9])
sed 's/[[:alpha:]]/L/g' filename # Replace letters
sed 's/[[:space:]]/X/g' filename # Replace whitespace charactersCuantificadores
Cero o más (*):
sed 's/ab*c/X/g' filename # Matches "ac", "abc", "abbc", "abbbc"
sed 's/[0-9]*/NUM/g' filename # Matches empty string or any digitsUno o más (\+ en BRE):
sed 's/[0-9]\+/NUM/g' filename # Matches one or more digits (GNU BRE extension)
sed 's/a\+/A/g' filename # Matches "a", "aa", "aaa", etc.Cuantificador uno-o-más portable
\+ en regex básica es una extensión GNU. Para scripts portables, usa -E (regex extendida) donde + funciona sin backslash: sed -E 's/[0-9]+/NUM/g' filename.
Ocurrencias exactas (\{n\}):
sed 's/[0-9]\{3\}/XXX/g' filename # Matches exactly 3 digits
sed 's/a\{2,4\}/A/g' filename # Matches 2 to 4 'a' charactersAnclas y límites
Anclas de línea:
sed 's/^Error/WARNING/' filename # Replace "Error" at line start
sed 's/end$/END/' filename # Replace "end" at line end
sed 's/^$/EMPTY/' filename # Replace empty linesLímites de palabra:
sed 's/\bcat\b/dog/g' filename # Replace whole word "cat" only
sed 's/\btest\b/exam/g' filename # Avoids matching "testing" or "retest"\b es una extensión de GNU
En BSD/macOS y busybox sed, \b se trata como un backslash literal + b. La sustitución no hace nada silenciosamente. Sin error, sin advertencia. En macOS, usa [[:<:]] y [[:>:]] para los límites de palabra. Para scripts portables, ancla con caracteres circundantes (espacios, puntuación, límites de línea).
Ejemplos avanzados prácticos
Formateo de números de teléfono:
# Transform (123) 456-7890 to 123-456-7890
sed 's/(\([0-9]\{3\}\)) \([0-9]\{3\}\)-\([0-9]\{4\}\)/\1-\2-\3/g' contacts.txtExtracción y enmascaramiento de emails:
# Replace email addresses with [EMAIL]
sed 's/[a-zA-Z0-9._%+-]\+@[a-zA-Z0-9.-]\+\.[a-zA-Z]\{2,\}/[EMAIL]/g' data.txtConversión de formato de fecha:
# Convert MM/DD/YYYY to YYYY-MM-DD
sed 's/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)/\3-\1-\2/g' dates.txtActualización de protocolos URL:
# Change HTTP to HTTPS
sed 's|http://\([^[:space:]]*\)|https://\1|g' urls.txtAgrupación y referencias hacia atrás
Grupos de captura con \(\) y referencias hacia atrás con \1, \2:
# Swap first and last names
sed 's/\([A-Za-z]*\) \([A-Za-z]*\)/\2, \1/g' names.txt
# Duplicate words detection and removal (GNU-only: uses \b and \+)
sed 's/\b\([a-zA-Z]\+\) \1\b/\1/g' text.txt
# Extract filename from path
sed 's/.*\/\([^\/]*\)$/\1/' paths.txtEjemplos de patrones complejos
Procesamiento de logs:
# Extract timestamp from log entries
sed 's/^\[\([0-9-: ]*\)\] .*/\1/' server.log
# Replace IP addresses with [IP]
sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/[IP]/g' access.logRefactorización de código:
# Update function calls: oldFunc(param) -> newFunc(param)
sed 's/oldFunc(\([^)]*\))/newFunc(\1)/g' code.js
# Convert 'single-quoted' strings to "double-quoted" (simple case)
sed -E "s/'([^']*)'/\"\1\"/g" script.jsEl ejemplo de comillas simples a dobles de arriba maneja casos simples. No maneja comillas simples escapadas (\') dentro de strings. Para eso, usa un parser de verdad o perl.
Expresiones regulares extendidas
Usando el flag -E para patrones mejorados:
# Alternation with |
sed -E 's/(cat|dog|bird)/animal/g' pets.txt
# Simplified quantifiers (no escaping needed)
sed -E 's/[0-9]{3}-[0-9]{2}-[0-9]{4}/XXX-XX-XXXX/g' ssn.txt
# Matching URL protocols
sed -E 's/(http|https):\/\/[^[:space:]]*/[URL]/g' text.txtNota: ERE de sed no tiene grupos sin captura ((?:...)). Todo grupo () captura. Usa -E por una sintaxis más limpia, no por comportamiento sin captura.
Prueba y depuración de expresiones regulares
Previsualiza coincidencias antes de reemplazar:
# Show what would be matched
grep 'pattern' filename
# Show line numbers with matches
grep -n 'pattern' filename
# Test with sed's print flag
sed -n 's/pattern/replacement/p' filenameConstruye patrones incrementalmente:
# Start simple
sed 's/[0-9]/X/' filename
# Add complexity gradually
sed 's/[0-9]\+/NUM/' filename
# Final complex pattern
sed 's/[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}/XXX-XX-XXXX/' filenameUsa --debug para trazar la ejecución (GNU sed 4.6+):
echo 1 | sed --debug 's/1/3/'Esto imprime el programa sed, anota cada línea de entrada mostrando el espacio PATTERN, y traza cada comando. Es la herramienta más útil para el “¿por qué mi comando sed hizo eso?”. El flag --debug es maduro en GNU sed 4.10. Se arregló un crash que ocurría cuando una etiqueta precedía a la opción.
Debugger externo: sedsed es un depurador y formateador para scripts de sed. Útil para recorrer paso a paso scripts complejos de múltiples comandos.
Advertencia sobre testers online: regex101 y herramientas similares usan PCRE, no POSIX BRE/ERE. Características como lookarounds, cuantificadores no-greedy (*?), y \d no se transfieren a sed. Verifica siempre los patrones con sed de verdad.
Técnicas avanzadas de sed y mejores prácticas
Procesamiento dirigido de líneas
Limita operaciones a rangos de línea específicos:
sed '1,10s/old/new/g' file.txt # Replace only in lines 1-10
sed '5,$s/old/new/g' file.txt # Replace from line 5 to end
sed '10s/old/new/g' file.txt # Replace only on line 10Apunta líneas por patrón:
sed '/pattern/s/old/new/g' file.txt # Replace only in lines containing "pattern"
sed '/^#/s/old/new/g' file.txt # Replace only in comment lines
sed '/ERROR/s/old/new/g' log.txt # Replace only in error linesTécnicas de previsualización y prueba
Previsualiza cambios antes de aplicar:
sed -n 's/old/new/p' file.txt # Show only changed lines
sed 's/old/new/g' file.txt | head -20 # Preview first 20 lines
sed 's/old/new/g' file.txt | diff file.txt - # Show differencesPrueba con números de línea:
nl file.txt | sed 's/old/new/g' # Show line numbers for contextTrabajando con caracteres especiales
Escapa caracteres literales:
sed 's/\./DOT/g' file.txt # Escape literal dots
sed 's/\*/STAR/g' file.txt # Escape literal asterisks
sed 's/\$/DOLLAR/g' file.txt # Escape literal dollar signs
sed 's/\//SLASH/g' file.txt # Escape literal forward slashesUsa delimitadores alternativos:
sed 's|/old/path|/new/path|g' file.txt # Use | for paths
sed 's#http://old#https://new#g' file.txt # Use # for URLs
sed 's@old@new@g' file.txt # Use @ as delimiterEscapa & en el string de reemplazo:
& en el reemplazo significa “toda la coincidencia”. Un & literal en una URL o una reescritura de query-string corromperá tu salida:
echo 'foo' | sed 's/foo/A & B/' # → "A foo B" (probably not intended)
echo 'foo' | sed 's/foo/A \& B/' # → "A & B" (literal ampersand)Esto muerde a la gente cuando reescribe URLs con parámetros de query (¶m=value). Escapa siempre el & literal en el reemplazo con \&.
Quoting de shell y sustitución de variables
Cuando los patrones de sed vienen de variables (común en scripts de actualización de config), el quoting del shell se vuelve delicado:
# Single quotes: no variable expansion (safe for literal patterns)
sed 's/old/new/g' file.txt
# Double quotes: variables expand, but /, &, \ in values collide with sed
KEY="old/path"
VAL="new/path"
sed "s|$KEY|$VAL|g" config.txt # Use | delimiter when values contain /
# Always quote filenames in batch loops
for file in *.txt; do
sed -i.bak 's/old/new/g' "$file"
done
# Use -- to stop option parsing for filenames starting with -
sed -i.bak 's/old/new/g' -- "-weird-name.txt"Para más sobre las diferencias de quoting del shell, mira el quoting entre Bash y Zsh.
Procesamiento por lotes de múltiples archivos
Procesa todos los archivos de un tipo:
find . -name "*.txt" -exec sed -i 's/old/new/g' {} \;
find . -name "*.conf" -exec sed -i.bak 's/old/new/g' {} \;Usando xargs para eficiencia:
find . -name "*.txt" | xargs sed -i 's/old/new/g'
find . -name "*.js" -print0 | xargs -0 sed -i 's/console.log/logger.debug/g'Bucle por los archivos:
for file in *.txt; do
sed -i.bak 's/old/new/g' "$file"
echo "Processed: $file"
doneArchivos de config con symlink
sed -i reemplaza el symlink con un archivo regular, rompiendo el enlace. Usa sed -i --follow-symlinks 's/old/new/' /path/to/symlink en GNU sed para editar el archivo destino. Esto importa para directorios de configuración como /etc/nginx/sites-enabled/. GNU sed 4.10 arregló una condición de carrera TOCTOU en --follow-symlinks.
Para más consejos de procesamiento de texto en Linux, mira cómo extraer texto en la línea de comandos de Linux.
Técnicas avanzadas de patrones
Usando referencias hacia atrás para reemplazos complejos:
# Swap two words
sed 's/\(foo\) \(bar\)/\2 \1/g' file.txt
# Duplicate text
sed 's/\(important\)/\1 \1/g' file.txt
# Rearrange data fields
sed 's/\([^,]*\),\([^,]*\),\([^,]*\)/\3,\1,\2/' data.csvOperaciones múltiples en secuencia:
sed -e 's/old1/new1/g' -e 's/old2/new2/g' -e 's/old3/new3/g' file.txtReemplazos condicionales:
# Replace only if line contains specific pattern
sed '/contains_this/{s/old/new/g;}' file.txt
# Replace in specific sections
sed '/START/,/END/{s/old/new/g;}' file.txtOptimización de rendimiento
Usa el locale C para trabajo pesado en ASCII:
LC_ALL=C sed -E 's/[0-9]+/NUM/g' bigfile.txtEl locale por defecto hace coincidencia de caracteres consciente de Unicode, que es más lenta. Poner LC_ALL=C fuerza coincidencia de bytes ASCII y puede ser significativamente más rápido en archivos grandes con sustituciones pesadas en regex. Haz benchmark con tus propios datos.
Otros consejos de rendimiento:
# Skip the g flag when you only need the first match per line
sed 's/old/new/' file.txt
# One sed pass with semicolons beats multiple sed processes
sed 's/old1/new1/g; s/old2/new2/g; s/old3/new3/g' file.txt
# Use specific patterns to reduce processing
sed '/pattern/s/old/new/g' file.txtEstrategias de seguridad y backup
Haz backup siempre de los archivos importantes:
cp original.txt original.txt.backup
sed -i.$(date +%Y%m%d) 's/old/new/g' original.txtPrueba primero con datos de muestra:
head -100 largefile.txt > sample.txt
sed 's/old/new/g' sample.txt # Test your pattern
# If good, apply to original:
sed -i.backup 's/old/new/g' largefile.txtEdición in-place atómica (temp + mv):
sed -i no es verdaderamente atómico. Escribe a un archivo temporal y renombra. Para archivos de configuración críticos, el patrón explícito temp + mv te da más control:
sed 's/old/new/' config.conf > config.conf.tmp && mv config.conf.tmp config.confEnvuélvelo con un trap para limpieza en caso de fallo:
trap 'rm -f config.conf.tmp' EXIT
sed 's/old/new/' config.conf > config.conf.tmp && mv config.conf.tmp config.conf
trap - EXITCompensación: mv cambia el inodo, lo que importa si otro proceso tiene el archivo en mmap o si un file watcher monitoriza cambios de inodo.
Usa control de versiones:
git add file.txt # Stage current version
sed -i 's/old/new/g' file.txt # Make changes
git diff # Review changesMira los comandos de Git para más sobre usar el control de versiones como red de seguridad.
CI/CD e idempotencia
Sed idempotente en CI/CD
s/old/new/g no es idempotente si new contiene old. Por ejemplo, s/foo/foobar/g corrido dos veces produce foobarbar. Para ediciones de config en CI/CD que se re-ejecutan en cada deploy, protégelo con un patrón de dirección, comprueba primero con grep, o usa una herramienta que sea idempotente de forma nativa.
Códigos de salida:
0: éxito1: comando o regex inválido2: no puede abrir el archivo de entrada4: error de E/S o error de runtime grave
Puedes poner códigos de salida personalizados con q N o Q N (extensión GNU):
# Exit with code 2 if "ERROR" is found
sed '/ERROR/{q 2;}' logfile.txtModo sandbox (GNU sed):
sed --sandbox 's/old/new/g' untrusted.txt--sandbox rechaza los comandos e (ejecutar), w (escribir) y r (leer). Úsalo cuando corres sed sobre entrada no confiable en pipelines.
Procesamiento delimitado por nulo:
find . -name "*.txt" -print0 | xargs -0 sed -i.bak 's/old/new/g'El flag -z / --null-data (GNU sed) procesa entrada delimitada por NUL, que combina con find -print0 y sort -z para manejar con seguridad nombres de archivo con espacios.
Ejemplos prácticos de flujo de trabajo
Actualizaciones de archivos de configuración:
# Update server configuration across multiple files
find /etc/nginx -name "*.conf" -exec sed -i.backup \
-e 's/old-server.com/new-server.com/g' \
-e 's/port 8080/port 80/g' {} \;Refactorización de código:
# Update function names in JavaScript files
find ./src -name "*.js" -exec sed -i \
's/oldFunction/newFunction/g' {} \;Procesamiento de logs:
# Clean and standardize log files
sed -e 's/DEBUG/[DEBUG]/g' \
-e 's/ERROR/[ERROR]/g' \
-e 's/INFO/[INFO]/g' app.log > standardized.logErrores comunes a evitar
- Olvidar escapar caracteres especiales.
.,*,$,[,\tienen todos significado especial en regex. - No probar los patrones antes de aplicarlos a archivos importantes. Previsualiza siempre con stdout primero.
- Usar reemplazo global cuando solo quieres la primera ocurrencia. Omite el flag
g. - No hacer backup de archivos antes de la edición in-place. Usa
-i.bakocp. - Hacer patrones demasiado amplios. Coincidir texto no deseado con
.*o un.sin escapar. - Usar escapes solo-GNU en scripts portables.
\b,\t,\+fallan silenciosamente en macOS/Alpine. - Combinar
-ncon-i. Trunca el archivo a cero bytes. - Olvidar que
&en el reemplazo significa “toda la coincidencia”. Escapa el&literal como\&.
Consejos pro
- Empieza con patrones simples y añade complejidad gradualmente
- Usa
greppara probar tus patrones antes de usarlos ensed - Usa
--debug(GNU sed 4.6+) para trazar la ejecución cuando los patrones se comportan mal - Usa
LC_ALL=Cpara procesamiento más rápido de datos ASCII - Mantén una colección de patrones sed probados para reutilizar
- Documenta las expresiones regulares complejas para referencia futura
- Sabe cuándo dejar de usar sed. Para ramificaciones, hold space, o slurps multilínea, usa
awko Python.
Conclusión
El comando s de sed es la herramienta correcta para ediciones de texto de una línea orientadas a líneas. Maneja actualizaciones de configuración, limpieza de datos y reemplazos por lotes sin cargar el archivo completo en memoria.
Lo clave a recordar: prueba sin -i primero, usa -i.bak para backups, y sabe qué sabor de sed estás corriendo. GNU sed en Linux, BSD sed en macOS, y busybox sed en Alpine se comportan todos diferente para -i, \b, \t, y el flag I. Escribe el sed para la máquina donde corre.
Para transformaciones complejas que involucren ramificaciones, hold space, o procesamiento multilínea, usa awk o Python en su lugar. Haz siempre backup de tus datos antes de ediciones in-place, y practica incrementalmente con archivos de muestra.


