Substituir sequência multilinha nos arquivos

17

Eu tenho vários arquivos que quero atualizar substituindo uma sequência de linhas múltiplas por outra sequência de linhas múltiplas. Algo ao longo das linhas de:

* Some text, 
* something else
* another thing

E eu quero substituí-lo por:

* This is completely
* different text

O resultado seria que, após a substituição, o arquivo que contém o primeiro bloco de texto agora conterá a segunda sequência (o restante do arquivo permanecerá inalterado).

Parte do problema é que tenho que encontrar a lista de arquivos a serem atualizados no sistema de arquivos. Eu acho que posso usar grep para isso (embora, novamente, isso não seja tão fácil de fazer com strings de várias linhas) e canalizá-lo no sed, talvez?

Existe uma maneira fácil de fazer isso? Sed é uma opção, mas é complicado porque eu tenho que adicionar \ n etc. Existe uma maneira de dizer "pegue a entrada deste arquivo, combine-a com esses arquivos e substitua-a pelo conteúdo desse outro arquivo"? Posso usar python, se necessário, mas quero algo rápido e simples; portanto, se houver um utilitário disponível, prefiro usá-lo do que escrever meu próprio script (que sei fazer).

ventsyv
fonte
Você provavelmente deve usar perl para isso. stackoverflow.com/questions/1030787/…
orion 26/01
3
Então, você deseja corresponder some text, something else another thingse ele abrange ou não várias linhas? Ou você só quer combinar some text,\nsomething else\nanotherthing?
mikeserv
2
Edite sua pergunta e esclareça qual é exatamente o conteúdo de cada arquivo e qual é a saída desejada.
jimmij
A cadeia de caracteres abrange várias linhas. Prefiro desconsiderar o espaço em branco ao fazer a correspondência / substituição, pois pode não ser absolutamente o mesmo, mas não é grande coisa se eu apenas fizer a correspondência de 1 a 1 (novas linhas e tudo).
ventsyv

Respostas:

12

Substitua "Some ... \ n ... Thing" pelo conteúdo do arquivo "new" em um ou mais arquivos de entrada

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
  1. -i mudar input.txt diretamente
  2. -p0 slurp arquivo de entrada e imprima-o no final
  3. s/regexp/.../s no regexp .é.|\n
  4. s/.../exp/e substituir por eval(exp)
  5. novo - um arquivo contendo o texto de substituição (este é um texto completamente ... diferente)
  6. se útil, você pode expandir o texto original s/Some text\n...\n...thing\n/...
JJoao
fonte
Como posso fazer o mesmo com um arquivo chamado say "before" para procurar o conteúdo (várias linhas) desse arquivo? Eu tentei, mas não funciona.
Kvothe
@Kvothe, precisamos de mais detalhes ... Assumindo que "antes" não tem caracteres especiais, você pode tentarperl -i -p0e ' $b= `cat before`; s/$b/Some thing\n/se' input.txt ...
JJoao
E assumindo que o "antes" contém todos os caracteres especiais (novas linhas, barras, colchetes), exceto 'e `.
Kvothe
5
sed -e :n -e '$!N;/\n.*\n/!{$!bn
};  s/some text,\n* *something else\n* *another thing/this is completely\
different text/;P;D' <infile

Receio que você tenha dificuldades em encontrar uma solução que atenda a você até elaborar uma descrição concreta do problema - mas é para isso que o controle de qualidade é mais adequado. Talvez isso lhe dê uma idéia - ele sempre manterá três linhas no espaço do padrão de cada vez - com um visor de duas linhas - enquanto desliza para frente através do arquivo de entrada apenas uma linha de cada vez.

Ele deve ser capaz de corresponder à sua cadeia de caracteres, seja ela de várias linhas ou não - até três, ou seja. Mas não há disposições para espelhar essa disposição na substituição - ela abrange sempre duas linhas, conforme escrito.

mikeserv
fonte
0

Não é forte (porque não chechou a segunda corda, mas é fácil de resolver) e pode ser que não seja compilador posix, mas muito simples:

sed '/^Some text/{:1;/another thing$/!{N;b 1}
     s/.*/this is completely\ndifferent text/g}' input.txt

O primeiro comando adiciona linhas de Algum texto até encontrar outra coisa e a segunda linha altera-a para outro texto.

NOTA A limitação é que alguns textos devem sempre ser seguidos por outra coisa .

Costas
fonte
O problema é que a cadeia pode ser mais de 2 linhas (até uma dúzia ou mais) e pode conter outras coisas que precisam poder ser escapado, tais como guias, etc. *
ventsyv
@ventsyv Não há problema com o número de linhas ou separadores - o script verifica apenas o início e o fim. É bastante suficiente se a string de início é excepcionalmente, pode marcar o texto para mudar . Se não houver melhor, mostre o exemplo de entrada para produzir o padrão correto.
Costas