Ось ще sed:
sed -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn' \
-eb -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et -e\} -eP\;D <in >out
Це робиться так, як ви просите. Він просто працює на стеку - будує його тоді, коли це необхідно і протягом необхідного періоду між появами коментованих рядків, а також скидає старий буфер на користь нового коментованого рядка далі на вході, коли він знайде його. Картина...

Вибачте, я не знаю, чому я це зробив. Але це прийшло в голову.
У будь-якому випадку, він sedрозповсюджує свої буфери між кожним останнім коментованим рядком у будь-якій серії, ніколи не зберігаючи жодного більше у своєму буфері, ніж це необхідно для точного відстеження останнього коментованого події, і якщо в будь-який момент він стикається з останнім рядком, роблячи це, він спробує остаточний gоператор виконання лобла та гілка tоцінює друк всього буфера, інакше він видасть Pусі ті рядки, які він випускає зі свого буфера, як тільки це з'явиться.
Я думаю, саме це наблизило гармошки ...
printf %s\\n \#alice \#bob charlie dotan eric \
\#alice \#bob charlie dotan eric \
\#alice \#bob charlie dotan eric |
sed -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn' \
-eb -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et -e\} -eP\;D
#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric
Існує лише одна різниця між цією командою і командою вище, і це команда look вгорі. Коли ми lпоглянемо на sedпростір шаблону, як він працює, ми можемо краще зрозуміти, що відбувається за лаштунками, і краще зрозуміти, як спрямовувати свої зусилля.
У цьому випадку ми можемо спостерігати sedвведення стека до тих пір, поки не знайдеться друге явище \n#.*\ndotanвведення, і коли воно починає друкувати попередній рядок за один раз. Це якось круто. Я багато чому навчився, працюючи над цим.