sed: reemplace la cadena con el contenido del archivo


22

Tengo dos archivos: file1y file2.

file1 tiene los siguientes contenidos:

---
  host: "localhost"
  port: 3000
  reporter_type: "zookeeper"
  zk_hosts: 
    - "localhost:2181"

file2contiene una dirección IP ( 1.1.1.1)

Lo que quiero hacer es reemplazar localhostcon 1.1.1.1, para que el resultado final sea:

---
  host: "1.1.1.1"
  port: 3000
  reporter_type: "zookeeper"
  zk_hosts: 
    - "1.1.1.1:2181"

Yo he tratado:

sed -i -e "/localhost/r file2" -e "/localhost/d" file1
sed '/localhost/r file2' file1 |sed '/localhost/d'
sed -e '/localhost/r file2' -e "s///" file1

Pero obtengo la línea completa reemplazada o la IP va a la línea después de la que necesito modificar.


1
No estoy seguro, pero ¿ cat file1 | sed -e 's/localhost/1.1.1.1/g'funciona?
— dchirikov

1
Mira el \rcomando sed.
— Kevin

Respuestas:


14

Aquí hay una sedsolución:

% sed -e "s/localhost/$(sed 's:/:\\/:g' file2)/" file1
---
  host: "1.1.1.1"
  port: 3000
  reporter_type: "zookeeper"
  zk_hosts: 
    - "1.1.1.1:2181"

Debe usar sed -ipara hacer el cambio en el lugar.

Si puede usar awk, aquí hay una forma de hacerlo:

% awk 'BEGIN{getline l < "file2"}/localhost/{gsub("localhost",l)}1' file1
---
  host: "1.1.1.1"
  port: 3000
  reporter_type: "zookeeper"
  zk_hosts: 
    - "1.1.1.1:2181"

44
+1 para awk. Me imagino que sed es capaz de esto, pero será terriblemente torpe. ¡Aquí es donde awkbrilla!
— HalosGhost

1
@HalosGhost: Parece que tanto tú como yo entendimos mal la pregunta de OP, actualicé mi respuesta.
— Cuonglm

La sustitución del comando para la sedsolución debe ser doblemente citada en caso de que el archivo contenga espacios o caracteres globales.
— Graeme

@Graeme: ¡Gracias, actualizado! Siéntase libre de hacer una edición.
— Cuonglm

2
Necesitas escapar de ambos /y &en la sustitución. Eso es"$(sed 's:[/\\&]:\\&:g' file2)"
— Toby Speight, el

6

Puede leer el archivo con la cadena de reemplazo usando la sustitución del comando de shell, antes de sedusarlo. Entonces sedverá solo una sustitución normal:

sed "s/localhost/$(cat file2)/" file1 > changed.txt


18
¿Funciona esto en archivos con líneas múltiples y archivos con caracteres especiales?
— Trevor Hickey

99
@TrevorHickey no lo hace. Sed simplemente falla con un error de "comando 's' no terminado".
— DarioP

1

Intenta usar

join file1 file2

y luego, elimine los campos no deseados.


1

También tuve este "problema" hoy: cómo reemplazar un bloque de texto con el contenido de otro archivo.

Lo resolví haciendo una función bash (que se puede reutilizar en scripts).

[cent@pcmk-1 tmp]$ cat the_function.sh
# This function reads text from stdin, and substitutes a *BLOCK* with the contents from a FILE, and outputs to stdout
# The BLOCK is indicated with BLOCK_StartRegexp and BLOCK_EndRegexp
#
# Usage:
#    seq 100 110 | substitute_BLOCK_with_FILEcontents '^102' '^104' /tmp/FileWithContents > /tmp/result.txt
function substitute_BLOCK_with_FILEcontents {
  local BLOCK_StartRegexp="${1}"
  local BLOCK_EndRegexp="${2}"
  local FILE="${3}"
  sed -e "/${BLOCK_EndRegexp}/a ___tmpMark___" -e "/${BLOCK_StartRegexp}/,/${BLOCK_EndRegexp}/d" | sed -e "/___tmpMark___/r ${FILE}" -e '/___tmpMark___/d'
}

[cent@pcmk-1 tmp]$
[cent@pcmk-1 tmp]$
[cent@pcmk-1 tmp]$ cat /tmp/FileWithContents
We have deleted everyhing between lines 102 and 104 and
replaced with this text, which was read from a file
[cent@pcmk-1 tmp]$
[cent@pcmk-1 tmp]$
[cent@pcmk-1 tmp]$ source the_function.sh
[cent@pcmk-1 tmp]$ seq 100 110 | substitute_BLOCK_with_FILEcontents '^102' '^104' /tmp/FileWithContents > /tmp/result.txt
[cent@pcmk-1 tmp]$
[cent@pcmk-1 tmp]$
[cent@pcmk-1 tmp]$ cat /tmp/result.txt
100
101
We have deleted everyhing between lines 102 and 104 and
replaced with this text, which was read from a file
105
106
107
108
109
110
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.