don's pode ser melhor na maioria dos casos, mas caso o arquivo seja realmente grande e você não consiga sedlidar com um arquivo de script tão grande (o que pode acontecer em mais de 5000 linhas de script) , aqui está o seguinte sed:
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Este é um exemplo do que é chamado de janela deslizante na entrada. Ele funciona criando um buffer antecipado de $Blinhas -count antes de tentar imprimir qualquer coisa.
E, na verdade, provavelmente devo esclarecer meu argumento anterior: o limitador de desempenho primário para essa solução e don's estará diretamente relacionado ao intervalo. Esta solução irá diminuir com intervalo maior tamanhos , enquanto Don irá diminuir com intervalo maior frequência . Em outras palavras, mesmo que o arquivo de entrada seja muito grande, se a ocorrência real do intervalo ainda for muito pouco frequente, sua solução provavelmente é o caminho a percorrer. No entanto, se o tamanho do intervalo for relativamente gerenciável e provavelmente ocorrer com freqüência, então essa é a solução que você deve escolher.
Então, aqui está o fluxo de trabalho:
- Se
$matchfor encontrado no espaço do padrão precedido por uma linha de \new, elimina sedrecursivamente Dcada linha de \new que o precede.
- Eu estava limpando
$matcho espaço do padrão completamente antes - mas lidar facilmente com a sobreposição, deixar um ponto de referência parece funcionar muito melhor.
- Também tentei
s/.*\n.*\($match\)/\1/fazê-lo de uma só vez e desviar do loop, mas quando $A/$Bsão grandes, o Dloop elete se mostra consideravelmente mais rápido.
- Em seguida, puxamos a
Nlinha ext de entrada precedida por um \ndelimitador de linha ew e tentamos novamente Dexcluir uma /\n.*$match/vez mais, referindo-se à nossa expressão regular usada mais recentemente com //.
- Se o espaço do padrão corresponder
$match, ele poderá fazê-lo apenas $matchno início da linha - todas as $Blinhas anteriores foram limpas.
- Então começamos a repetir depois
$A.
- Cada execução deste ciclo vamos tentar
s///ubstitute para &si o $Ath \npersonagem ewline no espaço de padrões, e, se bem sucedida, test nos ramificar - e toda a nossa $Atampão epois - fora do roteiro inteiramente para iniciar o script ao longo do topo com a próxima linha de entrada, se houver.
- Se o
test não for bem-sucedido, bvoltaremos ao :trótulo op e recuaremos para outra linha de entrada - possivelmente iniciando o loop se $matchocorrer durante a coleta $Aposterior.
- Se passar por um
$matchcircuito de função, então vamos tentar print a $última linha, se é isso, e se !não tentar s///ubstitute para &si o $Bth \npersonagem ewline no espaço padrão.
- Também determinaremos
tisso e, se for bem-sucedido, ramificaremos para o :Prótulo da rint.
- Caso contrário, voltaremos à
:toperação e obteremos outra linha de entrada anexada ao buffer.
- Se fizermos o rint , o rint
:Pserá eliminado até o primeiro ewline no espaço do padrão e reexecutar o script de cima com o que resta.PD\n
E desta vez, se estivéssemos fazendo A=2 B=2 match=5; seq 5 | sed...
O espaço do padrão para a primeira iteração no :Print seria semelhante a:
^1\n2\n3$
E é assim que sedreúne seu $Bbuffer anterior. E assim sedimprime $Bnas linhas de contagem de saída atrás da entrada que ela coletou. Isto significa que, dado nosso exemplo anterior, sedseria Print 1para a saída, e depois Delete isso e enviar de volta para o topo do script um espaço padrão que se parece com:
^2\n3$
... e na parte superior do script, a Nlinha de entrada ext é recuperada e, portanto, a próxima iteração se parece com:
^2\n3\n4$
E assim, quando encontramos a primeira ocorrência de 5in input, o espaço do padrão se parece com:
^3\n4\n5$
Em seguida, o Dloop elete entra em ação e, quando termina, parece:
^5$
E quando a Nlinha de entrada ext é puxada, sedatinge EOF e sai. Naquela época, apenas Pas linhas 1 e 2 foram criadas.
Aqui está um exemplo de execução:
A=8 B=7 match='[24689]0'
seq 100 |
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Isso imprime:
1
2
3
4
5
6
7
8
9
10
11
12
29
30
31
32
49
50
51
52
69
70
71
72
99
100