don's pode ser melhor na maioria dos casos, mas caso o arquivo seja realmente grande e você não consiga sed
lidar 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 $B
linhas -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
$match
for encontrado no espaço do padrão precedido por uma linha de \n
ew, elimina sed
recursivamente D
cada linha de \n
ew que o precede.
- Eu estava limpando
$match
o 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/$B
são grandes, o D
loop elete se mostra consideravelmente mais rápido.
- Em seguida, puxamos a
N
linha ext de entrada precedida por um \n
delimitador de linha ew e tentamos novamente D
excluir 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 $match
no início da linha - todas as $B
linhas anteriores foram limpas.
- Então começamos a repetir depois
$A
.
- Cada execução deste ciclo vamos tentar
s///
ubstitute para &
si o $A
th \n
personagem ewline no espaço de padrões, e, se bem sucedida, t
est nos ramificar - e toda a nossa $A
tampã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
t
est não for bem-sucedido, b
voltaremos ao :t
rótulo op e recuaremos para outra linha de entrada - possivelmente iniciando o loop se $match
ocorrer durante a coleta $A
posterior.
- Se passar por um
$match
circuito de função, então vamos tentar p
rint a $
última linha, se é isso, e se !
não tentar s///
ubstitute para &
si o $B
th \n
personagem ewline no espaço padrão.
- Também determinaremos
t
isso e, se for bem-sucedido, ramificaremos para o :P
rótulo da rint.
- Caso contrário, voltaremos à
:t
operação e obteremos outra linha de entrada anexada ao buffer.
- Se fizermos o rint , o rint
:P
será eliminado até o primeiro ewline no espaço do padrão e reexecutar o script de cima com o que resta.P
D
\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 :P
rint seria semelhante a:
^1\n2\n3$
E é assim que sed
reúne seu $B
buffer anterior. E assim sed
imprime $B
nas linhas de contagem de saída atrás da entrada que ela coletou. Isto significa que, dado nosso exemplo anterior, sed
seria P
rint 1
para a saída, e depois D
elete 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 N
linha 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 5
in input, o espaço do padrão se parece com:
^3\n4\n5$
Em seguida, o D
loop elete entra em ação e, quando termina, parece:
^5$
E quando a N
linha de entrada ext é puxada, sed
atinge EOF e sai. Naquela época, apenas P
as 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