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 sedgé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
$matchse trouve dans l'espace de motif précédé d'une ligne \nélectronique, supprimera sedrécursivement Dchaque 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/$Best grande, la Dboucle elete se révèle considérablement plus rapide.
- Ensuite, nous tirons sur la
Nligne d'entrée ext précédée d'un \ndé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,
$matchil ne peut le faire qu'avec $matchen tête de ligne - toutes les $Blignes précédentes ont été effacées.
- Nous commençons donc en boucle sur
$After.
- Chaque terme de cette boucle , nous allons tenter de
s///ubstitute pour &lui - même le $Ae \ncaractère ewline dans l' espace de modèle, et, en cas de succès, l' tEst nous branche - et tout notre $Atampon 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'
test ne réussit pas, nous allons branch vers l' :tétiquette d'opération et recurse pour une autre ligne d'entrée - éventuellement recommencer la boucle si $matchse produit lors de la collecte $After.
- Si nous obtenons passé une
$matchboucle de fonction, nous allons essayer de pRint la $dernière ligne si cela est, et si !ne pas essayer de s///ubstitute pour &lui - même le $Be \ncaractère ewline dans l' espace modèle.
- Nous l'
testimerons également, et si cela réussit, nous passerons à l' :Pétiquette rint.
- Si ce n'est pas le cas, nous allons revenir à
:top et obtenir une autre ligne d'entrée ajoutée au tampon.
- Si nous faisons à
:PRint nous PRint alors Délete jusqu'à la première \newline 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 à :Print ressemblerait à:
^1\n2\n3$
Et c'est ainsi que sedrassemble son $Btampon efore. Et donc sedimprime sur les $Blignes de sortie -comptes derrière l'entrée qu'il a recueillies. Cela signifie que, compte tenu de notre exemple précédent, sedse PRint 1à la sortie, puis Delete et que renvoyer au début du script un espace de motif qui ressemble à :
^2\n3$
... et en haut du script, la Nligne 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 5in input, l'espace de motif ressemble en fait à:
^3\n4\n5$
Ensuite, la Dboucle elete entre en jeu et quand elle est terminée, elle ressemble à:
^5$
Et lorsque la Nligne d'entrée ext est tirée, sedfrappe EOF et quitte. À ce moment-là, il n'a encore Pimprimé 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