sed - remplace la chaîne par le contenu du fichier

22

J'ai deux fichiers: file1et file2.

file1 a le contenu suivant:

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

file2contient une adresse IP ( 1.1.1.1)

Ce que je veux faire, c'est le remplacer localhostpar 1.1.1.1, pour que le résultat final soit:

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

J'ai essayé:

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

Mais soit je fais remplacer la ligne entière, soit l'adresse IP va à la ligne après celle que je dois modifier.

Jay Kah
la source
1
pas sûr, mais ça cat file1 | sed -e 's/localhost/1.1.1.1/g'marche?
dchirikov
1
Regardez la \rcommande sed.
Kevin

Réponses:

14

Voici une sedsolution:

% 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"

Vous devez utiliser sed -ipour effectuer le changement sur place.

Si vous pouvez utiliser awk, voici une façon de procéder:

% 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"
cuonglm
la source
4
+1 pour awk. J'imagine sed est capable de cela, mais ce sera terriblement maladroit. C'est là que awkbrille!
HalosGhost
1
@HalosGhost: Il me semble que vous avez mal compris la question OP, j'ai mis à jour ma réponse.
cuonglm
La substitution de commande pour la sedsolution doit être entre guillemets au cas où le fichier contient des espaces ou des caractères globaux.
Graeme
@Graeme: Merci, mis à jour! N'hésitez pas à faire une retouche.
cuonglm
2
Vous devez vous échapper à la fois /et &dans la substitution. C'est"$(sed 's:[/\\&]:\\&:g' file2)"
Toby Speight
6

Vous pouvez lire le fichier avec la chaîne de remplacement en utilisant la substitution de commandes shell, avant de l' sedutiliser. Donc, sedne verra qu'une substitution normale:

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

Volker Siegel
la source
18
Est-ce que cela fonctionne sur les fichiers multi-lignes et les fichiers avec des caractères spéciaux?
Trevor Hickey
9
@TrevorHickey ce n'est pas le cas. Sed échoue simplement avec une erreur de "commande non terminée".
DarioP
1

Essayez d'utiliser

join file1 file2

puis supprimez tous les champs indésirables.

unnut
la source
1

J'ai également eu ce "problème" aujourd'hui: comment remplacer un bloc de texte par le contenu d'un autre fichier.

Je l'ai résolu en créant une fonction bash (qui peut être réutilisée dans des 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
zipizap
la source