Дон може бути кращим у більшості випадків, але про всяк випадок, якщо файл дійсно великий, і ви не можете отримати 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
перш ніж щось намагатися надрукувати.
Насправді, мабуть, я повинен уточнити свій попередній пункт: основний обмежувач продуктивності і для цього рішення, і для дона буде безпосередньо пов'язаний з інтервалом. Це рішення сповільнюватиметься з більшими розмірами інтервалів , тоді як донські сповільнюватимуться з більшими інтервальними частотами . Іншими словами, навіть якщо вхідний файл дуже великий, якщо фактичний інтервал зустрічається ще дуже рідко, то його рішення, ймовірно, має пройти. Однак якщо розмір інтервалу є відносно керованим і, ймовірно, трапляється часто, то це рішення, яке ви повинні вибрати.
Ось ось робочий процес:
- Якщо
$match
він знайдеться в просторі шаблону, який передує \n
ewline, sed
буде рекурсивно вибирати D
кожну \n
лінію ewline, яка їй передує.
$match
Раніше я повністю очищав простір шаблону - але, щоб легко впоратися з перекриттям, залишається орієнтир, який працює набагато краще.
- Я також намагався
s/.*\n.*\($match\)/\1/
спробувати отримати його за один раз і відхилити цикл, але коли $A/$B
вони великі, D
елегантний цикл виявляється значно швидше.
- Потім ми вводимо
N
рядок вхідного сигналу, який передує \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
оп і отримаємо інший рядок введення, доданий до буфера.
- Якщо ми зробимо це для
:P
рингту, ми будемо P
ринг, а потім D
піднімемо до першого \n
ewline у просторі шаблону і повторимо сценарій зверху з тим, що залишилося.
І так цього разу, якби ми робили A=2 B=2 match=5; seq 5 | sed...
Простір шаблону для першої ітерації в :P
rint виглядатиме так:
^1\n2\n3$
Ось як sed
збирає свій $B
попередній буфер. І так sed
друкує $B
рядки виводу- рахунку за зібраним входом. Це означає , що, з огляду на наш попередній приклад, 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