Sed: Localizando e substituindo um padrão que envolve a próxima linha

2

Eu quero encontrar e substituir um padrão, mas ele também envolve a próxima linha, preciso encontrar uma maneira de lidar com isso

Algo que parece:

....tr("Changes to output mappings will be deleted. "
"There is no undo available. Do you want to continue?"));

para se transformar em algo como

...."Changes to output mappings will be deleted. "
"There is no undo available. Do you want to continue?");

(o ... é o código anterior)

Até agora, tenho código como (funciona para uma única linha, mas não para texto / código):

sed -i 's/tr(\([^)]*\))//I' $file_t

Como eu faria isso?

    
por user186523 26.08.2016 / 20:08

1 resposta

4

Para o caso em que os comandos tr( estão sempre distribuídos em duas linhas, tente:

$ sed  '/tr(/N; s/tr(\([^)]*\))//I' "$file_t"
...."Changes to output mappings will be deleted. "
"There is no undo available. Do you want to continue?");

A única alteração aqui é a adição de /tr(/N . Para qualquer linha que corresponda a tr( , leia a próxima linha e adicione-a ao espaço padrão ( N ).

Para alterar o arquivo, use -i :

sed  -i.bak '/tr(/N; s/tr(\([^)]*\))//I' "$file_t"

Versão mais robusta

Se for possível que os comandos tr(...) apareçam em uma linha, em duas linhas ou em mais de duas linhas, precisamos alterar um pouco a lógica:

sed  '/tr(/{ :a; s/tr(\([^)]*\))//I; t; N; ba}' filename

Isso procura linhas que contenham tr( . Para qualquer uma dessas linhas, os comandos em chaves, {...} , são executados. Para essas linhas, a substituição é primeiramente tentada apenas nessa linha. Se a substituição acontecer, o comando t informará que concluímos esta linha. Se isso não aconteceu, o que significa que não houve fechamento ) , então a próxima linha é lida em ( N ) e sed filiais de volta ao rótulo a ( ba ) e a substituição é tentada novamente. Isso se repete até que linhas suficientes sejam lidas para encontrar o ) .

Como exemplo, aqui está um arquivo com tr(...) distribuído em uma, duas e três linhas:

$ cat filename
tr("abc");
....tr("Changes to output mappings will be deleted. "
"There is no undo available. Do you want to continue?"));
tr("one
two
three");

Aqui está a saída:

$ sed  '/tr(/{ :a; s/tr(\([^)]*\))//I; t; N; ba}' filename
"abc";
...."Changes to output mappings will be deleted. "
"There is no undo available. Do you want to continue?");
"one
two
three";

Distinguindo entre tr(...) e Ptr(...)

Para garantir que substituímos apenas tr e não Ptr ou Str , precisamos garantir que tr comece em um limite de palavra. Com o GNU sed (Linux), um limite de palavra é denotado \b :

sed  '/\btr(/{ :a; s/\btr(\([^)]*\))//I; t; N; ba}' filename

Usando o BSD (OSX) sed, o seguinte pode funcionar:

sed  '/[[:<:]]tr(/{ :a; s/[[:<:]]tr(\([^)]*\))//I; t; N; ba}' filename
    
por 26.08.2016 / 20:15

Tags