Zamień ciąg znaków na zawartość pliku za pomocą sed

23

Mam dwa różne pliki:

Plik 1

/home/user1/  
/home/user2/bin  
/home/user1/a/b/c

Plik 2

<TEXT1>
<TEXT2>

Chcę wymienić <TEXT1>z pliku Plik2 z treścią File1 użyciu sed. Próbowałem tego polecenia, ale nie otrzymałem właściwego wyniku:

cat File2|sed "s/<TEXT1>/$(cat File1|sed 's/\//\\\//g'|sed 's/$/\\n/g'|tr -d "\n")/g"

Możesz również użyć innych narzędzi, aby rozwiązać ten problem.

chanchal1987
źródło
Wklej ten komunikat o błędzie, abyśmy mogli zlokalizować jego źródło. Powiedz nam również, jakiej sedimplementacji używasz. Twój kod działa dla mnie z GNU sed.
manatwork
Przepraszamy, brak błędu. Nie otrzymuję pożądanej wydajności. Wyjście jest jak /home/user1/ n/home/user2/bin n/home/user1/a/b/cn <TEXT2>. Brak nowych linii.
chanchal1987
Nie jestem pewien, czy miałoby to zastosowanie w konkretnym przypadku, ale za pomocą diffi patchnarzędzia pozwalają dość łatwo zastąpić niektóre linie w pliku innymi liniami.
Stéphane Gimenez
1
Btw, używanie losowych danych zebranych za $()pomocą skryptu sed powoduje, że moje oczy krwawią. Nigdy nie używaj danych zewnętrznych w miejscach, w których niektóre znaki są interpretowane ze szczególnym znaczeniem.
Stéphane Gimenez
Podobne pytanie: Zastąp wzór w pliku zawartością innego pliku
Toby Speight

Odpowiedzi:

24

Oto rozwiązanie skryptu sed (łatwiejsze dla oczu niż próba umieszczenia go w jednej linii w wierszu poleceń):

/<TEXT1>/ {
  r File1
  d
}

Uruchamianie:

$ sed -f script.sed File2
/home/user1/
/home/user2/bin
/home/user1/a/b/c
<TEXT2>
Kusalananda
źródło
Dzięki, to działa. Ale nie chcę używać żadnego innego pliku skryptu. Czy jest jakieś wbudowane rozwiązanie?
chanchal1987
Jasne: sed '/<TEXT1>/{rFile1^Md^M}' File2gdzie „^ M” oznacza naciśnięcie klawisza Return. Problem polega na tym, że sed naprawdę potrzebuje znaków nowej linii w {...}, aby rozgraniczić polecenie r i d.
Kusalananda
6
z bash, łańcuchy w stylu posix są nieco czystsze:sed $'/<TEXT1>/ {r File1\n d}'
glenn jackman
9
Również z -e dla jednej sed -e '/<TEXT1>/{r File1' -e 'd}' File2
linijki
1
A jeśli zamiast zastąpić całą linię zawierającą <TEXT1>, chcę po prostu zastąpić sam łańcuch, pozostawiając resztę linii nienaruszoną? Text1: <TEXT1>do Text1: <file_contents>.
Robin Winslow
9

Długo zajęło mi znalezienie tego rozwiązania za pomocą zamiany var. Wszystkie rozwiązania sed nie działały dla mnie, ponieważ albo usuwają pełne wiersze, albo zastępują niepoprawnie.

FILE2=$(<file2)
FILE1=$(<file1)
echo "${FILE2//TEXT1/$FILE1}" 

Zastępuje wszystkie wystąpienia TEKSTU 1 w pliku 2 względem zawartości pliku 1. Cały pozostały tekst pozostaje nietknięty.

marcas756
źródło
bardzo dobrze. być może szybszy niż sedteż, ponieważ te „rozszerzenia” (inaczej zamienniki) są wbudowane w powłokę ( bashprzynajmniej)
żółto-żółty
7

Odpowiadam, ponieważ w niektórych przypadkach metoda diff/ patchmoże być interesująca. Aby zdefiniować podstawienie linii zawartych w pliku blob1przez linie zawarte w blob2użyciu:

diff -u blob1 blob2 > patch-file

Na przykład, jeśli blob1zawiera:

hello
you

i blob2zawiera:

be
welcome
here

wygenerowane patch-filebędą:

--- blob1   2011-09-08 16:42:24.000000000 +0200
+++ blob2   2011-09-08 16:50:48.000000000 +0200
@@ -1,2 +1,3 @@
-hello
-you
+be
+welcome
+here

Teraz możesz zastosować tę poprawkę do dowolnego innego pliku:

patch somefile patch-file

Zastąpi on hello, youliniach be, welcome, herelinie w somefile.

Stéphane Gimenez
źródło
jest to naprawdę sprytne, ale byłoby lepiej, gdybyś mógł zautomatyzować go w skrypcie
qodeninja