sed - zamień ciąg znaków na zawartość pliku

22

Mam dwa pliki: file1i file2.

file1 ma następującą zawartość:

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

file2zawiera adres IP ( 1.1.1.1)

Co chcę zrobić, to wymienić localhostz 1.1.1.1tak, że końcowy wynik jest:

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

Próbowałem:

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

Ale albo wymienię całą linię, albo adres IP przejdzie do linii po tej, którą muszę zmodyfikować.

Jay Kah
źródło
1
nie jestem pewien, ale czy cat file1 | sed -e 's/localhost/1.1.1.1/g'działa?
dchirikov
1
Spójrz na \rkomendę sed.
Kevin,

Odpowiedzi:

14

Oto sedrozwiązanie:

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

Powinieneś użyć, sed -iaby wprowadzić zmianę w miejscu.

Jeśli możesz użyć awk, oto jeden ze sposobów:

% 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
źródło
4
+1 dla awk. Wydaje mi się, że sed jest do tego zdolny, ale będzie to strasznie niezdarne. To gdzie awkbłyszczy!
HalosGhost
1
@HalosGhost: Wydaje się, że zarówno ja, jak i ty źle zrozumiałeś pytanie OP, zaktualizowałem swoją odpowiedź.
cuonglm
Podstawienie polecenia dla sedrozwiązania powinno być podwójnie cytowane, jeśli plik zawiera spacje lub znaki globu.
Graeme
@Graeme: Dzięki, zaktualizowano! Dokonaj edycji.
cuonglm
2
Musisz uciec zarówno w podstawieniu, jak /i &w obu . To jest"$(sed 's:[/\\&]:\\&:g' file2)"
Toby Speight,
6

Możesz przeczytać plik z ciągiem zastępującym, używając podstawienia poleceń powłoki, zanim sedzostanie użyty. Więc sedbędzie widać tylko normalne zmiany:

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

Volker Siegel
źródło
18
Czy działa to w przypadku plików wielowarstwowych i plików ze znakami specjalnymi?
Trevor Hickey,
9
@TrevorHickey nie. Sed po prostu kończy się niepowodzeniem z błędem „niezakończonego polecenia”.
DarioP,
1

Spróbuj użyć

join file1 file2

a następnie usuń niechciane pola.

unxnut
źródło
1

Miałem też dzisiaj ten „problem”: jak zastąpić blok tekstu zawartością z innego pliku.

Rozwiązałem to, tworząc funkcję bash (która może być ponownie wykorzystana w skryptach).

[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
źródło