Если существующие закомментированные строки образуют единый непрерывный блок, то вместо этого вы можете сопоставить с первой закомментированной строки, закомментировав только те строки вплоть до вашего конечного шаблона, которые еще не закомментированы
sed '/^#/,/dotan/ s/^[^#]/#&/' file
Если существующие комментарии не являются смежными, то из-за жадной природы совпадения диапазона sed я думаю, что вам нужно сделать что-то вроде
tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac
то есть совпадение вверх от конечного шаблона до «первого» комментария - очевидно, это не очень удобно, если вы хотите получить решение на месте.
Вы можете обрабатывать оба случая (закомментированные строки в одном смежном блоке или перемежающиеся между некомментированными строками) одним sedвызовом:
sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile
Это обрабатывает только линии в 1,/PATTERN/диапазоне. Это xменяет пространство удержания w. шаблонное пространство каждый раз, когда строка закомментирована (таким образом, в буфере удержания никогда не бывает более одной закомментированной строки), и добавляет каждую строку, которая не закомментирована, к Hстарому пространству (когда на 1-ой строке, 1dи, соответственно 1h, также необходима для удаления начальной пустая строка в буфере удержания).
Когда она достигает соответствия линии PATTERN, он также присоединяет его к Hстарому буфера, е xизменяет буфера , а затем заменяет каждый \newline символ в шаблоне пространстве с \newline и а #(то есть, все строки шаблона теперь будут начинаться с #, включение первой строки в качестве первой строки в области удержания всегда является строкой с комментариями).
С образцом infile:
alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry
Бег:
sed '1,/dotan/{ # if line is in this range -start c1
/^#/{ # if line is commented -start c2
x # exchage hold space w. pattern space
1d # if 1st line, delete pattern space
b # branch to end of script
} # -end c2
//!{ # if line is not commented -start c3
H # append to hold space
/dotan/!{ # if line doesn't match dotan -start c4
1h # if 1st line, overwrite hold space
d # delete pattern space
} # -end c4
//{ # if line matches dotan -start c5
x # exchage hold space w. pattern space
s/\n/&#/g # add # after each newline character
} # -end c5
} # -end c3
}' infile # -end c1
выходы:
alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry
поэтому он комментирует только строки от (и исключая) #charlieдо (и включая) dotanи оставляя другие строки без изменений.
Конечно, это предполагает, что перед совпадением всегда есть хотя бы одна закомментированная строка PATTERN. Если это не так, вы можете добавить дополнительную проверку перед заменой:/^#/{s/\n/&#/g}
Спасибо, у меня будет немало, чтобы узнать из этого ответа!
dotancohen
Подожди, я, должно быть, облажался. Это не о последней серии закомментированных строк? Нет, я понимаю, это так. Последняя серия + дотан. Довольно чертовски умный.
mikeserv
1
Вы всегда найдете лучшие вопросы. Проклятый дотан бросил меня на некоторое время - возможно, все еще делает, я еще не проверял это. спасибо дон
Это делает, как вы просите. Он просто работает со стеком - строит его при необходимости и столько времени, сколько необходимо между вхождениями закомментированных строк, и сбрасывает старый буфер в пользу новой закомментированной строки далее на входе, когда находит ее. Картина...
Извините, я не знаю, почему я это сделал. Но это пришло в голову.
В любом случае, sedраспределяет свои буферы между каждой последней закомментированной строкой в любом ряду, никогда не сохраняя в своем буфере больше, чем необходимо для точного отслеживания последнего закомментированного вхождения, и, если в любое время он встречает последнюю строку при этом, он попытается последний gоператор выполнения lobal и ветвь создают 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«s шаблона , как это работает , мы можем получить лучшее представление о том, что происходит за кулисами , и лучшее понимание того , как направить свои усилия.
В этом случае мы можем наблюдать за sedвводом в стек до тех пор, пока не обнаружим второе вхождение \n#.*\ndotanна входе, и когда он начнет печатать предыдущую строку за раз. Это круто. Я многому научился, работая над этим.
Очень хорошо, спасибо! Последний абзац с пояснениями потрясающий, я тоже потрачу немало времени на изучение этого поста. Хороший стек!
dotancohen
1
@dotancohen - это был действительно хороший вопрос. Посмотрите на редактирование, чтобы увидеть стек .
mikeserv
2
Я замечаю в истории редактирования запись Handle many dotans. Я уверен, что это худший кошмар моей жены.
dotancohen
1
@dotancohen - да, это было сложно. Вещи, как #\ndotan\ndotanтрудно для этих вещей. Я имею в виду, когда я говорю это хороший вопрос. Я думаю , что я получил его почти идеально, но одна проблема , которую вы могли бы столкнуться, если ваш комментарий блоки отделены друг от друга на 1000 строк - это будет замедлять его. Вы можете вставить что-то вроде s/\n/&/150;tin перед первым /\n#, чтобы разбить буфер, например, если он занимает 150 строк. И вообще, может быть, это именно то, чего она ждала все это время !
Вот еще один
sed
:Это делает, как вы просите. Он просто работает со стеком - строит его при необходимости и столько времени, сколько необходимо между вхождениями закомментированных строк, и сбрасывает старый буфер в пользу новой закомментированной строки далее на входе, когда находит ее. Картина...
Извините, я не знаю, почему я это сделал. Но это пришло в голову.
В любом случае,
sed
распределяет свои буферы между каждой последней закомментированной строкой в любом ряду, никогда не сохраняя в своем буфере больше, чем необходимо для точного отслеживания последнего закомментированного вхождения, и, если в любое время он встречает последнюю строку при этом, он попытается последнийg
оператор выполнения lobal и ветвь создаютt
весь буфер для печати, иначе он будетP
набирать все те строки, которые он освобождает из своего буфера, как только это произойдет.Я думаю, это то, что принесло аккордеоны в голову ...
Есть только одно различие между этой командой и той, что выше, и это команда
l
ook вверху. Когда мыl
ООК вsed
«s шаблона , как это работает , мы можем получить лучшее представление о том, что происходит за кулисами , и лучшее понимание того , как направить свои усилия.В этом случае мы можем наблюдать за
sed
вводом в стек до тех пор, пока не обнаружим второе вхождение\n#.*\ndotan
на входе, и когда он начнет печатать предыдущую строку за раз. Это круто. Я многому научился, работая над этим.источник
Handle many dotans
. Я уверен, что это худший кошмар моей жены.#\ndotan\ndotan
трудно для этих вещей. Я имею в виду, когда я говорю это хороший вопрос. Я думаю , что я получил его почти идеально, но одна проблема , которую вы могли бы столкнуться, если ваш комментарий блоки отделены друг от друга на 1000 строк - это будет замедлять его. Вы можете вставить что-то вродеs/\n/&/150;t
in перед первым/\n#
, чтобы разбить буфер, например, если он занимает 150 строк. И вообще, может быть, это именно то, чего она ждала все это время !