Прокоментуйте всі рядки з останнього коментованого рядка до рядка "foo"


12

Розглянемо текстовий файл users.txt:

#alice
#bob
charlie
dotan
eric

Мені потрібно прокоментувати все, починаючи з (виключно) останнього коментованого рядка до (включно) dotan. Це результат:

#alice
#bob
#charlie
#dotan
eric

Чи є приємний sedoneliner для цього? Я буду задоволений будь-яким інструментом, не просто sed, насправді.

Наразі я отримую номер рядка останнього коментованого рядка так:

$ cat -n users.txt | grep '#' | tail -n1
  2 #bob

Потім я додаю його та коментую sed:

$ sed -i'' '3,/dotan/ s/^/#/' users.txt

Я знаю, що я міг би бути розумним і вклав це все разом з деякими bcв потворний однолінійний. Невже має бути чистіший спосіб?

Відповіді:


5

Як щодо

perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file

або, та ж сама ідея:

awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file

7

Якщо існуючі коментовані рядки утворюють єдиний суміжний блок, то замість цього ви можете порівняти з першого коментованого рядка, коментуючи лише ті рядки до та включаючи ваш кінцевий шаблон, який ще не коментується

sed '/^#/,/dotan/ s/^[^#]/#&/' file

Якщо існуючі коментарі не є суміжними, то через жадібний характер сімейства діапазонів sed я думаю, вам потрібно буде зробити щось на кшталт

tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac

тобто співставити вгору від кінцевого шаблону до «першого» коментаря - очевидно, це не так зручно, якщо ви хочете, щоб все-таки вирішити місце.


4

Ви можете обробити обидва випадки (коментовані рядки в одному суміжному блоці або перемежовані між некоментованими рядками) за допомогою одного 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старого буфера, e xзмінює буфери, а потім замінює кожен \nсимвол ewline у ​​просторі шаблону \newline та a #(тобто всі рядки в просторі шаблону тепер почнуться #, включаючи перший рядок, оскільки перший рядок у просторі утримування завжди є коментованим рядком).
Зразком 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
Ви завжди знаходите найкращі питання. Проклятий дотан мене кинув на деякий час - можливо, все одно, я ще не перевірив це. дякую, доне.
mikeserv

2

Ось ще 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введення, і коли воно починає друкувати попередній рядок за один раз. Це якось круто. Я багато чому навчився, працюючи над цим.


Дуже приємно, дякую! Заключний абзац з поясненнями приголомшливий, я також проведу досить часу, вивчаючи цю посаду. Гарний стек!
dotancohen

1
@dotancohen - це було справді гарне питання. Погляньте на правки, щоб побачити стек .
mikeserv

2
Я помічаю в історії редагування запис Handle many dotans. Я впевнений, що це найгірший кошмар моєї дружини.
dotancohen

1
@dotancohen - так, це було важко. Такі речі #\ndotan\ndotanважко для цих речей. Я маю на увазі це, коли говорю це гарне запитання. Я думаю , що я отримав його майже ідеально, але одна проблема , яку ви могли б зіткнутися, якщо ваш коментар блоки відокремлені один від одного на 1000 рядків - це буде сповільнювати його. Ви можете вставити щось на кшталт s/\n/&/150;tперед тим, як перше /\n#, щоб вирвати буфер, якщо, наприклад, він охоплює 150 рядків. І все одно, можливо, це саме те, чого вона чекала все це !
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.