don może być lepszy w większości przypadków, ale na wypadek, gdyby plik był naprawdę duży i nie możesz sobie sedporadzić z tak dużym plikiem skryptu (co może się zdarzyć przy ponad 5000 liniach skryptu) , oto proste 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'
Jest to przykład tak zwanego przesuwanego okna na wejściu. Działa poprzez budowanie bufora wyprzedzającego z $B-count linii przed próbą wydrukowania czegokolwiek.
I właściwie powinienem wyjaśnić moją poprzednią kwestię: główny ogranicznik wydajności zarówno dla tego rozwiązania, jak i dla dona, będzie bezpośrednio związany z interwałem. To rozwiązanie będzie spowalniać przy większych rozmiarach interwałów , podczas gdy don będzie spowalniać przy większych częstotliwościach interwałów . Innymi słowy, nawet jeśli plik wejściowy jest bardzo duży, jeśli faktyczne występowanie interwału jest nadal bardzo rzadkie, jego rozwiązanie jest prawdopodobnie dobrym rozwiązaniem. Jeśli jednak wielkość interwału jest względnie łatwa do zarządzania i często występuje, należy wybrać to rozwiązanie.
Oto przepływ pracy:
- Jeśli
$matchzostanie znaleziony w przestrzeni wzorca poprzedzonej \newline, sedrekurencyjnie usunie Dkażdą \newline, która go poprzedza.
- Wyczyściłem
$matchprzestrzeń wzorów całkowicie wcześniej - ale aby łatwo poradzić sobie z nakładaniem się, pozostawienie punktu orientacyjnego wydaje się działać znacznie lepiej.
- Próbowałem też
s/.*\n.*\($match\)/\1/spróbować za jednym razem i uniknąć pętli, ale gdy $A/$Bsą duże, Dpętla elete okazuje się znacznie szybsza.
- Następnie wyciągnij w
Nlinii EXT wejścia poprzedzone \nseparatora ewline i spróbuj ponownie DsuĹ /\n.*$match/ponownie odwołując się do naszej ostatnio używanego wyrażenia regularnego w / //.
- Jeśli przestrzeń wzoru pasuje,
$matchto można to zrobić tylko $matchna początku linii - wszystkie wcześniejsze $Blinie zostały usunięte.
- Zaczynamy więc
$Azapętlać.
- Każdy przebieg tej pętli będziemy próbować
s///ubstitute na &sobie $Ath \ncharakter ewline w przestrzeni wzorca, a jeśli się powiedzie, test nas oddział - i cały nasz $Abufor fter - z skryptu w całości, aby uruchomić skrypt w ciągu od góry z następnym wierszem wprowadzania, jeśli istnieje.
- Jeśli
test się nie powiedzie, bwrócimy do :tetykiety operacji i przejdziemy do innej linii danych wejściowych - być może zaczniemy pętlę, jeśli $matchwystąpi podczas zbierania $After.
- Jeśli przejdziemy przez
$matchpętlę funkcji, spróbujemy pprzeszukać $ostatnią linię, jeśli to jest, a jeśli !nie, postaramy się s///zbudować dla &siebie znak $Btej \nlinii w przestrzeni wzorca.
- Będziemy
test to także, a jeśli jest to sukces będziemy rozgałęziać na :Petykiecie rint.
- Jeśli nie, wrócimy do
:toperacji i otrzymamy kolejną linię wejściową dołączoną do bufora.
- Jeśli zrobimy to do
:Printowania, zrobimy Pto następnie Ddo pierwszej \newline w przestrzeni wzorów i ponownie uruchom skrypt od góry z tym, co pozostało.
I tym razem, gdybyśmy to robili A=2 B=2 match=5; seq 5 | sed...
Przestrzeń wzorów dla pierwszej iteracji w :Print wyglądałaby następująco:
^1\n2\n3$
I w ten sposób sedgromadzi swój $Bbufor. I tak seddrukuje do wyjścia $B-count linii za wejście to zebrał. Oznacza to, że biorąc pod uwagę nasz poprzedni przykład, sedby Prukuj 1do wyjścia, a następnie DsuĹ że i wysłać z powrotem do górnej części skryptu przestrzeń która wygląda jak wzór:
^2\n3$
... a na górze skryptu Npobierana jest linia wejściowa ext, więc następna iteracja wygląda następująco:
^2\n3\n4$
Kiedy więc znajdziemy pierwsze wystąpienie danych 5wejściowych, przestrzeń wzoru wygląda tak:
^3\n4\n5$
Następnie Duruchamia się pętla elete i po jej zakończeniu wygląda następująco:
^5$
A kiedy Nlinia wejściowa ext zostanie wyciągnięta, seduderza EOF i kończy pracę. Do tego czasu ma tylko Plinie w odcieniach 1 i 2.
Oto przykładowy przebieg:
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'
To drukuje:
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