Don peut être mieux dans la plupart des cas, mais juste au cas où le fichier est vraiment gros et que vous ne pouvez pas sed
gérer un fichier de script aussi volumineux (ce qui peut arriver à environ 5000+ lignes de script) , le voici avec plain 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'
Ceci est un exemple de ce qu'on appelle une fenêtre coulissante en entrée. Il fonctionne en construisant une anticipation tampon$B
lignes -count avant même d' essayer d'imprimer quoi que ce soit.
Et en fait, je devrais probablement clarifier mon point précédent: le limiteur de performance principal pour cette solution et pour Don sera directement lié à l'intervalle. Cette solution va ralentir avec un intervalle de plus grandes tailles , alors que don de ralentiront avec un intervalle de plus grandes fréquences . En d'autres termes, même si le fichier d'entrée est très volumineux, si l'occurrence réelle de l'intervalle est encore très peu fréquente, sa solution est probablement la voie à suivre. Cependant, si la taille de l'intervalle est relativement gérable et est susceptible de se produire souvent, c'est la solution que vous devez choisir.
Voici donc le workflow:
- Si
$match
se trouve dans l'espace de motif précédé d'une ligne \n
électronique, supprimera sed
récursivement D
chaque ligne \n
électronique qui la précède.
- J'éclaircissais
$match
train de vider complètement l'espace des motifs avant - mais pour gérer facilement les chevauchements, laisser un point de repère semble fonctionner beaucoup mieux.
- J'ai également essayé
s/.*\n.*\($match\)/\1/
d'essayer de l'obtenir en une seule fois et d'esquiver la boucle, mais lorsqu'elle $A/$B
est grande, la D
boucle elete se révèle considérablement plus rapide.
- Ensuite, nous tirons sur la
N
ligne d'entrée ext précédée d'un \n
délimiteur ewline et essayons une fois de plus d' D
éliminer un /\n.*$match/
en se référant à notre expression régulière w / la plus récemment utilisée //
.
- Si l'espace de motif correspond,
$match
il ne peut le faire qu'avec $match
en tête de ligne - toutes les $B
lignes précédentes ont été effacées.
- Nous commençons donc en boucle sur
$A
fter.
- Chaque terme de cette boucle , nous allons tenter de
s///
ubstitute pour &
lui - même le $A
e \n
caractère ewline dans l' espace de modèle, et, en cas de succès, l' t
Est nous branche - et tout notre $A
tampon de près avoir - sur le script entièrement pour lancer le script au- dessus de la partie supérieure avec la ligne d'entrée suivante, le cas échéant.
- Si l'
t
est ne réussit pas, nous allons b
ranch vers l' :t
étiquette d'opération et recurse pour une autre ligne d'entrée - éventuellement recommencer la boucle si $match
se produit lors de la collecte $A
fter.
- Si nous obtenons passé une
$match
boucle de fonction, nous allons essayer de p
Rint la $
dernière ligne si cela est, et si !
ne pas essayer de s///
ubstitute pour &
lui - même le $B
e \n
caractère ewline dans l' espace modèle.
- Nous l'
t
estimerons également, et si cela réussit, nous passerons à l' :P
étiquette rint.
- Si ce n'est pas le cas, nous allons revenir à
:t
op et obtenir une autre ligne d'entrée ajoutée au tampon.
- Si nous faisons à
:P
Rint nous P
Rint alors D
élete jusqu'à la première \n
ewline dans l' espace de configuration et exécutez à nouveau le script du haut avec ce qui reste.
Et donc cette fois, si nous faisions A=2 B=2 match=5; seq 5 | sed...
L'espace de motif pour la première itération à :P
rint ressemblerait à:
^1\n2\n3$
Et c'est ainsi que sed
rassemble son $B
tampon efore. Et donc sed
imprime sur les $B
lignes de sortie -comptes derrière l'entrée qu'il a recueillies. Cela signifie que, compte tenu de notre exemple précédent, sed
se P
Rint 1
à la sortie, puis D
elete et que renvoyer au début du script un espace de motif qui ressemble à :
^2\n3$
... et en haut du script, la N
ligne d'entrée ext est récupérée et donc l'itération suivante ressemble à:
^2\n3\n4$
Et donc quand nous trouvons la première occurrence de 5
in input, l'espace de motif ressemble en fait à:
^3\n4\n5$
Ensuite, la D
boucle elete entre en jeu et quand elle est terminée, elle ressemble à:
^5$
Et lorsque la N
ligne d'entrée ext est tirée, sed
frappe EOF et quitte. À ce moment-là, il n'a encore P
imprimé que les lignes 1 et 2.
Voici un exemple d'exécution:
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'
Cela 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