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?

smokris
fonte

Respostas:

36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file
Peter.O
fonte
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
smokris
fonte
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
Dr Kitty
fonte
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
Jetchisel
fonte
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,