Sed substituto com 3 linhas de janelas de correr

5

Eu preciso implementar uma janela deslizante de 3 linhas com Sed para alterar qualquer ocorrência das 3 seguintes linhas agrupadas em um arquivo de texto grande:

Fax: 05.11.22.33.44<LF>
<LF>
<LF>

com isso:

Fax: 05.11.22.33.44<LF>
###
<LF>

Eu tentei fazer isso com a seguinte linha de comando (sed executado em um arquivo de lote msdos, mas ele não funciona muito no meu bash linux):

sed -i ":a;$!N;s/\nFax: \([ 0-9\.]*\n\n\);tenough;$!ba;:enough/\nFax: ###\n/;$!ba;P;D" file.txt

O que há de errado?

    
por Syl87 27.06.2017 / 00:19

3 respostas

3

Você tem a parte P;D correta. O resto é uma tentativa fracassada de puxar linhas no espaço padrão até que uma substituição seja bem-sucedida, o que não é necessariamente uma coisa ruim, mas definitivamente não é uma janela deslizante. Você deve puxar em uma linha quando estiver na primeira linha e usar um ciclo N;P;D (dessa forma você sempre tem três linhas no espaço padrão) e tente substituir cada vez que você puxar uma nova linha

sed '1N;$!N;s/\(PATTERN\n\)\(\n\)$/###/;P;D' infile
    
por 27.06.2017 / 01:18
1

Eu acho que isto está perto da sua tentativa original de implementação:

sed ':a; $q; N; s/\(Fax:.*\n\)\n$/###\n/; 3,${P;D}; ba'

Ex.

$ sed ':a; $q; N; s/\(Fax:.*\n\)\n$/###\n/; 3,${P;D}; ba' input > output
$ diff -y input output
Fax: 05.11.22.33.44                                             Fax: 05.11.22.33.44
Fax: 05.11.22.33.44                                             Fax: 05.11.22.33.44

Fax: 05.11.22.33.44                                             Fax: 05.11.22.33.44
                                                              | ###

Fax: 05.11.22.33.44                                             Fax: 05.11.22.33.44
Fax: 05.11.22.33.44                                             Fax: 05.11.22.33.44
                                                              | ###

Fax: 05.11.22.33.44                                             Fax: 05.11.22.33.44

O truque é o 3,${P;D} , que mantém a janela de 3 linhas (estendendo uma linha do espaço padrão a cada volta, mas somente após a contagem de linhas atingir 3).

    
por 27.06.2017 / 02:35
-1

A solução da steeldriver tem uma vantagem: também pode funcionar em cinco linhas, sete ou mais trabalhos também. No meu caso: encontre a linha correspondente e substitua as duas antes, a correspondida e as duas linhas após a primeira parte da linha e, em seguida, um valor "Lista" vazio em vez do existente.

A entrada é abreviada, as linhas são originalmente > 2000 longos:

Frame 64 (List 213 [(LM 0 0 836 216 112 0.681952 0.260603)])
Frame 65 (List 236 [(LM 0 0 836 216 112 0.680071 0.187739)])
Frame 66 (List 235 [(LM 0 0 836 216 112 0.678168 0.315848)])
Frame 67 (List 98 [(LM 149 129 1456 216 112 0.525970 11.970105)])
Frame 68 (List 217 [(LM 0 4 1084 216 112 0.837058 0.658243)])
Frame 69 (List 212 [(LM 0 0 1084 216 112 0.829624 0.339764)])
Frame 70 (List 218 [(LM 0 0 1084 216 112 0.829624 0.200893)])

A linha de correspondência do comando Sed 67 (fora dos valores do whack) é:

sed -re ":a; $q; N; s/(Frame .[0-9] ).*(Frame .[0-9] ).*(Frame .[0-9] ).*LM\ [0-9][0-9][0-9].*(Frame .[0-9] ).*(Frame .[0-9] ).*/(List 0 \[\]\)\n\(List 0 \[\]\)\n\(List 0 \[\]\)\n\(List 0 \[\]\)\n\(List 0 \[\]\)/; 5,${P;D}; ba" transform1.trf > transform2.trf

O comando sed corresponde ao Frame 67, a saída é:

Frame 64 (List 213 [(LM 0 0 836 216 112 0.681952 0.260603) <cut>])
Frame 65 (List 0 [])
Frame 66 (List 0 [])
Frame 67 (List 0 [])
Frame 68 (List 0 [])
Frame 69 (List 0 [])
Frame 70 (List 218 [(LM 0 0 1084 216 112 0.829624 0.200893) <cut>])

Veja aqui link por que eu procurei por isso. Eu não tenho reputação suficiente para publicá-lo como comentário, ou para votar em uma solução, então eu postei dessa maneira. Outros podem ser capazes de usá-lo. Então, meus agradecimentos vão para a Steeldriver.

    
por 08.11.2017 / 00:10

Tags