Como substituir parte de um arquivo de texto entre marcadores por outro arquivo de texto?


26

Digamos que eu tenha um arquivo de texto como este:

# custom content section
a
b

### BEGIN GENERATED CONTENT
c
d
### END GENERATED CONTENT

Gostaria de substituir a parte entre as GENERATED CONTENTtags pelo conteúdo de outro arquivo.

Qual é a maneira mais simples de fazer isso?

Respostas:


36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file

Excelente. sedpode fazer muito mais do que apenas s/.../...!
DevSolar

Hmmm não funciona para mim, devo colocar o comando sed em uma linha?
Lzap

3
O r insert_filecomando deve ser a última coisa em sua linha. Observe que nem espaço em branco nem comentários são permitidos depois dele. O código foi testado usando o GNU sedcom a --posixopção ativada e funcionou como esperado, portanto, deve funcionar com qualquer posix compatível sed .
Peter.O

1
Santo Moly, isso é legal! Isso está acontecendo no meu dicionário sed! Soberbamente útil e lindamente simples. Obrigado!
precisa saber é o seguinte

2
Observe que uma edição no local exige que você capture a saída do sed (por exemplo output=$(sed -e "..." existing_file)) e execute a substituição em uma segunda passagem (por exemplo echo "$output" > existing_file), pois tentar redirecionar para um arquivo do qual você está lendo fará com que ele trunque antes da leitura do conteúdo.
Chris Tonkinson

5
newContent=`cat new_file`
perl -0777 -i -pe "s/(### BEGIN GENERATED CONTENT\\n).*(\\n### END GENERATED CONTENT)/\$1$newContent\$2/s" existing_file

Bom trabalho. Muito mais simples que o meu. :)
Dr. Kitty

4

Aviso: Definitivamente, essa não é a maneira mais simples de fazer isso. (EDIT: bash funciona; POSIX grep também é bom)

Se o texto principal estiver no arquivo "principal" e o conteúdo gerado estiver no arquivo "gen", você poderá fazer o seguinte:

#!/bin/bash
BEGIN_GEN=$(cat main | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
END_GEN=$(cat main | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
cat <(head -n $(expr $BEGIN_GEN - 1) main) gen <(tail -n +$(expr $END_GEN + 1) main) >temp
mv temp main

Isto funciona? Eu acho que sua última linha será aberta mainpara escrita, limpando-a, antes de ser lida pelo gato.
chepner

@chepner Crap, você está certo. O resto funciona, no entanto. Eu resolvo isso.
Dr Kitty

3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF

Usando um heredoc e o editor de linha de edição. A primeira linha dentro do heredoc é excluída 'd' a linha após '+' o '### BEGIN GENERATED ...' e a linha antes de '-' the '### END GENERATED ...' a segunda linha é inserir FILE2 após a linha ### END GERADO ...'
Jetchisel

Desculpe o que eu queria dizer era inserção FILE2 após a linha '### BEGIN GERADO ..'
Jetchisel

Acalme-se, pessoal, é afinal a minha primeira vez :-). Também eu poderia ter usado a palavra da mesma forma, mas a outra solução não usa heredocs, mas um printf e um pipe. QUALQUER FORMA desculpas se eu cometi um erro :-)
Jetchisel

Obrigado, muito legível! Btw - em vez de r FILE2você pode dizer r !commandpara ler de um script diferente.
Kos,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.