Como substituo várias linhas por uma única palavra no arquivo (substituição no local)?

9

O conteúdo do meu filenamearquivo é o seguinte (por exemplo):

My block of line starts from here 
START
First line
second line
third line
END
and end to here for example.

Quero substituir o bloco de linhas entre STARTe ENDcom apenas uma única palavra, por exemplo, com SINGLEWORD. Como abaixo:

My block of line starts from here 
SINGLEWORD
and end to here for example.

Eu posso encontrar meu bloco de linhas usando este comando:

grep -Pzo "START(.|\n)*END" filename

E o resultado da execução do comando acima será assim:

START
First line
second line
third line
END

Então eu usei este comando para combinar todas as linhas em uma única linha:

LAST_RESULT | sed -e :a -e '/$/N; s/\n/ /; ta'

Então eu vou receber este resultado:

START First line second line third line END

E com meu último comando, LAST_RESULTS | sed 's/.*/SINGLEWORD/'eu as altero para "SINGLEWORD"e obtenho esse resultado.

SINGLEWORD

Agora, o que eu quero é: Como posso usar este comando (ou o seu comando de sugestão) e substituir (no lugar) meu bloco de linhas pela palavra "SINGLEWORD"? E o resultado final será como este arquivo:

My block of line starts from here 
SINGLEWORD
and end to here for example.
αғsнιη
fonte

Respostas:

14

Isso pode ser feito com muita facilidade em perl:

$ perl -i -p0e 's/START.*?END/SINGLEWORD/s' file
$ cat file
My block of line starts from here 
SINGLEWORD
and end to here for example. 

Explicação

-0 define o separador de linhas como nulo

-paplique o script fornecido por -ecada linha e imprima essa linha

O modificador regexp:

  • /sTrate a string como uma única linha. Ou seja, altere .para corresponder a qualquer caractere, mesmo uma nova linha, que normalmente não corresponderia.

Por que ?:

  • Por padrão, um sub-padrão quantificado é "ganancioso", ou seja, corresponderá o maior número de vezes possível (dado um local de partida específico), enquanto ainda permite que o restante do padrão seja correspondido. Se você deseja que ele corresponda ao número mínimo de vezes possível, siga o quantificador com a ?.
Sylvain Pineau
fonte
@KasiyA: Usando seddeve ser possível, mas provavelmente mais difícil de ler (Olhe para esta questão )
Sylvain Pineau
Uma mais porque o meu padrão INÍCIO e FIM tem caracteres especiais ( /, *, ?) nele e estes são apenas exemplo. e você poderia explicar seu comando.
αғsнιη
@KasiyA você pode escapar de tais personagens com \ (exatamente como com sed): \/, \*,\?
Sylvain Pineau
@KasiyA eu tentei perl -i -p0e 's/\/\*.*?\*\//SINGLEWORD/sm'. Deveria funcionar #
394 Sylvain Pineau
@KasiyA Eu acho que eu sou feito com explicações agora;)
Sylvain Pineau
14

Eu queria saber se isso é possível sem perl, pythone outros. E eu encontrei esta solução usando sed:

$ sed ':a;N;$!ba;s/START.*END/SINGLEWORD/g' filename

Explicação:

  1. : a crie um rótulo 'a'
  2. N anexa a próxima linha ao espaço do padrão
  3. $! se não for a última linha , ba branch (vá para) rotule 'a'
  4. s substituto , /START.*END/por SINGLEWORD, / g correspondência global (quantas vezes for possível)

Foi encontrado aqui .

@ KasiyA, obrigado Eu aprendi muitas coisas interessantes!

c0rp
fonte