Substitua string pelo conteúdo de um arquivo usando sed

23

Eu tenho dois arquivos diferentes:

Arquivo1

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

Arquivo2

<TEXT1>
<TEXT2>

Eu quero substituir o <TEXT1>do File2 com o conteúdo do File1 usando sed. Eu tentei este comando, mas não obtendo saída adequada:

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

Você também pode usar outras ferramentas para resolver esse problema.

chanchal1987
fonte
Cole essa mensagem de erro para que possamos localizar sua fonte. Diga-nos também qual sedimplementação você está usando. Seu código funciona para mim com o GNU sed.
manatwork
Desculpe, não está recebendo um erro. Não estou obtendo a saída desejada. Saída é como /home/user1/ n/home/user2/bin n/home/user1/a/b/cn <TEXT2>. Não recebendo novas linhas.
chanchal1987
Não tenho certeza se isso se aplicaria no seu caso específico, mas as ferramentas com diffe patchpermitem substituir algumas linhas em um arquivo por outras com bastante facilidade.
Stéphane Gimenez
1
Aliás, usar dados aleatórios reunidos $()em um script sed faz meus olhos sangrarem. Nunca use dados externos em locais onde alguns caracteres são interpretados com significado especial.
Stéphane Gimenez

Respostas:

24

Aqui está uma solução de script sed (mais fácil para os olhos do que tentar colocá-la em uma linha na linha de comando):

/<TEXT1>/ {
  r File1
  d
}

Executando:

$ sed -f script.sed File2
/home/user1/
/home/user2/bin
/home/user1/a/b/c
<TEXT2>
Kusalananda
fonte
Obrigado, isso está funcionando. Mas não quero usar nenhum outro arquivo de script. Existe alguma solução em linha?
chanchal1987
Claro:, sed '/<TEXT1>/{rFile1^Md^M}' File2onde "^ M" é você pressionando return. O problema é que o sed realmente precisa das novas linhas dentro do {...} para delimitar os comandos re d.
Kusalananda
6
com bash, cordas de estilo POSIX são um pouco mais limpo:sed $'/<TEXT1>/ {r File1\n d}'
Glenn Jackman
9
Também com -e para um liner:sed -e '/<TEXT1>/{r File1' -e 'd}' File2
sdaau
1
E se, em vez de substituir toda a linha que contém <TEXT1>, eu apenas quero substituir a própria string, deixando o resto da linha intacta? Text1: <TEXT1>para Text1: <file_contents>.
Robin Winslow
9

Levei muito tempo para encontrar esta solução usando a substituição de var. Todas as soluções sed não funcionaram para mim, pois excluem linhas completas ou substituem incorretamente.

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

Substitui todas as ocorrências de TEXT1 no arquivo2 pelo conteúdo do arquivo1. Todo o outro texto permanece intocado.

marcas756
fonte
muito agradável. possivelmente mais rápido do que sedtambém, uma vez que essas "expansões" (também conhecidas como substituições) são incorporadas ao shell ( bashpelo menos)
amarelo-amarelado
7

Eu respondo porque o método diff/ patchpode ser interessante em alguns casos. Para definir uma substituição de linhas contidas no arquivo blob1por linhas contidas em blob2uso:

diff -u blob1 blob2 > patch-file

Por exemplo, se blob1contém:

hello
you

e blob2contém:

be
welcome
here

o gerado patch-fileserá:

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

Agora, você pode aplicar esse patch a qualquer outro arquivo:

patch somefile patch-file

Ele irá substituir hello, youlinhas por be, welcome, herelinhas em somefile.

Stéphane Gimenez
fonte
isso é realmente inteligente, mas seria melhor se você pudesse automatizá-lo em um script
qodeninja