don potrebbe essere migliore nella maggior parte dei casi, ma nel caso in cui il file sia davvero grande e non riesci sed
a gestire un file di script così grande (che può accadere a circa 5000+ righe di script) , eccolo qui 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'
Questo è un esempio di quella che viene chiamata una finestra scorrevole sull'input. Funziona costruendo un buffer look-$B
forward di -count prima di tentare di stampare qualsiasi cosa.
E in realtà, probabilmente dovrei chiarire il mio punto precedente: il principale limitatore di prestazioni sia per questa soluzione che per quella di don sarà direttamente correlato all'intervallo. Questa soluzione rallenterà con intervalli di dimensioni maggiori , mentre quella di don rallenterà con frequenze di intervallo maggiori . In altre parole, anche se il file di input è molto grande, se il verificarsi dell'intervallo effettivo è ancora molto raro, la sua soluzione è probabilmente la strada da percorrere. Tuttavia, se la dimensione dell'intervallo è relativamente gestibile ed è probabile che si verifichi spesso, questa è la soluzione che dovresti scegliere.
Quindi ecco il flusso di lavoro:
- Se
$match
si trova nello spazio del modello preceduto da una \n
ewline, elimina sed
ricorsivamente D
ogni \n
ewline che la precede.
$match
Prima stavo eliminando completamente lo spazio del modello, ma per gestire facilmente la sovrapposizione, lasciare un punto di riferimento sembra funzionare molto meglio.
- Ho anche cercato
s/.*\n.*\($match\)/\1/
di provare a farlo in una volta sola e schivare il loop, ma quando $A/$B
sono grandi, il D
loop elete si rivela notevolmente più veloce.
- Quindi inseriamo la
N
riga ext di input preceduta da un \n
delimitatore di ewline e proviamo ancora una volta a D
eliminare /\n.*$match/
una ancora facendo riferimento alla nostra espressione regolare usata più di recente w / //
.
- Se lo spazio del motivo corrisponde,
$match
allora può farlo solo con $match
all'inizio della linea - tutte le $B
linee precedenti sono state cancellate.
- Quindi iniziamo a fare un giro su
$A
fter.
- Ogni esecuzione di questo ciclo cercheremo di
s///
ubstitute per &
sé $A
l'esimo \n
carattere ewline nello spazio modello, e, in caso di successo, t
Est saranno noi ramo - e tutta la nostra $A
tampone opo - out dello script del tutto per avviare lo script sopra dall'alto con la successiva riga di input se presente.
- Se l'
t
est non è riuscita faremo b
ranch di nuovo alla :t
etichetta op e recurse per un'altra linea di input - possibilmente iniziare il ciclo su se $match
si verifica durante la raccolta $A
opo.
- Se otteniamo oltre un
$match
ciclo funzione, quindi cercheremo di p
Rint l' $
ultima riga, se questo è vero, e se !
non provate a s///
ubstitute per &
sé $B
l'esimo \n
carattere ewline nello spazio modello.
- Ci
t
Est questo, troppo, e se è successo ci ramo per l' :P
etichetta di Rint.
- Altrimenti torneremo all'operazione
:t
e aggiungeremo un'altra riga di input al buffer.
- Se ce la facciamo a
:P
rint, ci P
rintaccheremo, quindi D
elimineremo fino alla prima \n
ewline nello spazio modello e eseguiremo nuovamente lo script dall'alto con ciò che rimane.
E così questa volta, se lo stessimo facendo A=2 B=2 match=5; seq 5 | sed...
Lo spazio del modello per la prima iterazione a :P
rint sarebbe simile a:
^1\n2\n3$
Ed è così che sed
raccoglie il suo precedente $B
buffer. E così sed
stampa sull'output $B
delle linee di conteggio dietro l'input che ha raccolto. Questo significa che, dato il nostro esempio precedente, sed
sarebbero P
Rint 1
di uscita, e poi D
elete che e rispedire alla parte superiore dello script di uno spazio modello che assomiglia a:
^2\n3$
... e nella parte superiore dello script N
viene recuperata la riga di input ext e quindi la prossima iterazione appare come:
^2\n3\n4$
E così quando troviamo la prima occorrenza di 5
in input, lo spazio del pattern in realtà appare come:
^3\n4\n5$
Quindi D
entra in gioco il ciclo elete e quando è finito sembra:
^5$
E quando N
viene estratta la linea di input ext, sed
colpisce EOF e si chiude. A quel punto ha sempre e solo P
sfilato le righe 1 e 2.
Ecco un esempio:
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'
Che stampa:
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