don может быть лучше в большинстве случаев, но только в том случае, если файл действительно большой, и вы не можете sedобработать файл сценария такого большого размера (который может иметь место в более чем 5000 строк сценария) , вот это с простым 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'
Это пример того, что называется скользящим окном при вводе. Он работает путем создания упреждающего буфера $Bстрок -count, прежде чем пытаться что-либо напечатать.
И на самом деле, вероятно, я должен уточнить мой предыдущий пункт: основной ограничитель производительности как для этого решения, так и для Дон будет напрямую связан с интервалом. Это решение будет замедляться с большими интервальными размерами , в то время как Дон замедлится с большими интервальными частотами . Другими словами, даже если входной файл очень большой, если фактический интервал встречается все еще очень редко, то его решение, вероятно, является путем. Однако, если размер интервала относительно управляем и, вероятно, встречается часто, то это решение, которое вы должны выбрать.
Итак, вот рабочий процесс:
- Если
$matchон найден в пространстве шаблона, которому предшествует \newline, sedрекурсивно Dудалит каждую \newline, которая ему предшествует.
- Раньше
$matchя полностью очищал пространство шаблонов - но чтобы легко справиться с перекрытием, оставление ориентира, кажется, работает намного лучше.
- Я также попытался
s/.*\n.*\($match\)/\1/сделать это за один раз и уклониться от цикла, но когда он $A/$Bбольшой, Dцикл Elete оказывается значительно быстрее.
- Затем мы вытягиваем
Nстроку ввода ext, которой предшествует \nразделитель ewline, и снова Dпытаемся выбрать /\n.*$match/один раз, ссылаясь на наше последнее использованное регулярное выражение w / //.
- Если пространство образца совпадает,
$matchто это может быть сделано только в начале строки $match- все $Bпредыдущие строки были очищены.
- Итак, мы начинаем
$Aциклы после.
- Каждый запуск этого цикла мы будем пытаться
s///ubstitute для &себя $Aго \nсимвола ewline в пространстве картины, и, в случае успеха, tЭст произрастет нас - и весь наш $Aосле буфер - из сценария полностью запустить скрипт через сверху со следующей строкой ввода, если есть.
- Если
test не увенчался успехом, мы bвернемся к :tметке op и вернемся к другой строке ввода - возможно, начнем цикл снова, если $matchпроизойдет при сборе $After.
- Если пройти в
$matchпетлю функции, то мы будем стараться pРинт в $последнюю строку , если это, и если !не пытаться s///ubstitute для &себя $Bго \newline характер в пространстве картины.
- Мы тоже
tэто сделаем , и если это будет успешно, мы перейдем к :Pметке rint.
- Если нет, мы вернемся к
:top и добавим еще одну строку ввода в буфер.
- Если мы сделаем это для того, чтобы
:Pнабрать текст, мы будем Pпечатать, а затем Dподняться до первой \nстроки в шаблонном пространстве и перезапустить сценарий сверху с оставшимся.
И вот на этот раз, если бы мы делали A=2 B=2 match=5; seq 5 | sed...
Пространство шаблона для первой итерации в :Print будет выглядеть так:
^1\n2\n3$
И вот как sedсобирает свой $Before буфер. И поэтому sedпечатает в выходные $Bстроки -count за собранным вводом. Это означает, что, учитывая наш предыдущий пример, sedбудет Pвыведен 1вывод, а затем его Dвыбор и отправка обратно в верхнюю часть скрипта пространства шаблона, которое выглядит следующим образом:
^2\n3$
... и в верхней части скрипта Nизвлекается строка ввода ext, поэтому следующая итерация выглядит следующим образом:
^2\n3\n4$
И поэтому, когда мы находим первое вхождение 5во входных данных, пространство шаблона на самом деле выглядит так:
^3\n4\n5$
Затем Dвключается цикл Elete, и когда он проходит, это выглядит так:
^5$
И когда Nстрока ввода ext sedвыдвигается, нажимает EOF и выходит. К тому времени в нем были только когда-либо Pнабранные линии 1 и 2.
Вот пример запуска:
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'
Это печатает:
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