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.