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
он найден в пространстве шаблона, которому предшествует \n
ewline, sed
рекурсивно D
удалит каждую \n
ewline, которая ему предшествует.
- Раньше
$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
осле буфер - из сценария полностью запустить скрипт через сверху со следующей строкой ввода, если есть.
- Если
t
est не увенчался успехом, мы b
вернемся к :t
метке op и вернемся к другой строке ввода - возможно, начнем цикл снова, если $match
произойдет при сборе $A
fter.
- Если пройти в
$match
петлю функции, то мы будем стараться p
Ринт в $
последнюю строку , если это, и если !
не пытаться s///
ubstitute для &
себя $B
го \n
ewline характер в пространстве картины.
- Мы тоже
t
это сделаем , и если это будет успешно, мы перейдем к :P
метке rint.
- Если нет, мы вернемся к
:t
op и добавим еще одну строку ввода в буфер.
- Если мы сделаем это для того, чтобы
:P
набрать текст, мы будем P
печатать, а затем D
подняться до первой \n
строки в шаблонном пространстве и перезапустить сценарий сверху с оставшимся.
И вот на этот раз, если бы мы делали A=2 B=2 match=5; seq 5 | sed...
Пространство шаблона для первой итерации в :P
rint будет выглядеть так:
^1\n2\n3$
И вот как sed
собирает свой $B
efore буфер. И поэтому 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