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.


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"

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


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.


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.