Как я могу использовать sed или ex для замены блока (многострочный код) новым блоком текста (код)?

9

Я должен заменить большой блок текста (код сценария оболочки) в файле другим блоком текста.

Я впечатлен, как я могу использовать sed для замены многострочной строки? ответили antak и Multi-line заменить ответили Брюс Эдигер

Но у меня есть некоторые проблемы с их использованием.

  1. Antak уже упоминал в своем ответе, что потоковая передача всего file ( 1h;2,$H;$!d;g;) в буфер не рекомендуется для больших файлов, потому что это перегружает память.

  2. Я знаю, sedможет использоваться с функцией блока, чтобы сохранить текст вне блока без изменений. Я хочу использовать эту функцию. Но если я использую,

    sed -i '/marker1/,/marker2/s/.*/new text (code)/' filename
    

он будет вставлять новый текст (код) повторно для каждого потока. Следовательно, я должен сделать визуальный блок одним потоком, используя что-то похожее на то, что предлагал ранее Antak , но для блока (не для всего файла).

  1. Как упоминал Брюс Эдигер, можно добавить функцию добавления, exначинающуюся с aконца .(точка), но мой новый текст (код) содержит строки, начинающиеся с точки, что можно рассматривать как синтаксис точки добавления. Как я могу использовать это в этой ситуации?

  2. ex's dd' количество строк 'может удалить несколько строк, но если у меня есть блок между / marker1 / и / marker2 / с количеством строк не фиксированным (изменяющимся), должен быть заменен новым текстом (кодом), как это сделать Это ?

gibies
источник
Я нахожу ваше использование термина «визуальный блок» необычным и запутанным. Вы имеете в виду просто блок (группу) последовательных, полных строк?
Скотт
Да, я редактирую вопрос, чтобы избежать путаницы.
gibies
Что является источником для замены текста? Это в файле или "только в уме программистов"?
don_crissti
Это для ситуативного исправления сценария оболочки. Следовательно, источником заменяющего текста является ум программиста (или мастер-сценарий, над которым работает sedили exкоманда).
gibies
Дон Крисси: Я бы использовал rкоманду чтения файла, чтобы скопировать текст из другого файла, если исходный текст для замены находится в файле.
gibies

Ответы:

10

Я предлагаю использовать с командой висящей (которая по существу d далить в сочетании с более ppend, хотя Append применяется только для последней строки в диапазоне , который является именно то , что вы хотите здесь):

sed -i '/marker1/,/marker2/c\
New text 1\
New text 2' filename

Здесь используется sedсинтаксис GNU для редактирования на месте ( -i). В cостальном эта команда стандартна и переносима. GNU sedподдерживает:

sed '/marker1/,/marker2/cNew text 1\
New text 2' filename

как нестандартное расширение.

Символы новой строки и обратной косой черты должны быть экранированы (с обратной косой чертой) в тексте замены.

G-Man говорит: «Восстанови Монику»
источник
Команда изменения отлично работает для обоих sedи для обоих ex. Большое спасибо.
gibies
Есть ли способ избежать «\» и использовать здесь документ, sedкак в случае с exсинтаксисом, предложенным Брюсом Эдигером в многострочной замене .
gibies
Вам не понадобится обратная косая черта, если вы используете rкоманду, описанную в других ответах на этот вопрос. Я не уверен, как вы будете использовать здесь документ с sed.
G-Man говорит: «Восстановите Монику»
8

Использование GNU sed

Чтобы заменить строки, начинающие сопоставление строк 3и продолжающие сопоставление строк 5с New Code:

$ seq 8 | sed '/3/,/5/{/5/ s/.*/New Code/; t; d}'
1
2
New Code
6
7
8

Для строк в диапазоне /3/,/5/мы проверяем, соответствует ли строка 5(имеется в виду, что это последняя строка в группе), и, если это так, мы делаем замену для вставки New Code. Если подстановка была сделана, то tкоманда говорит sed перейти к концу команд (в этом случае New Codeпечатается). Если нет, dкоманда говорит sed удалить строку.

Все остальные строки печатаются нормально.

Чтобы изменить файл на месте, -iможно использовать параметр:

sed -i.bak '/3/,/5/{/5/ s/.*/New Code/; t; d}' file

Использование awk

Чтобы сделать то же самое с помощью awk:

$ seq 8 | awk '/3/,/5/{if (!f)print "New Code"; f=1; next}; 1'
1
2
New Code
6
7
8

Команда awk обрабатывает строки в диапазоне /3/,/5/специально. Для строк в этом диапазоне мы проверяем, fравен ли он нулю (то есть, является ли !fоно истинным), и, если это так, мы печатаем New Codeи устанавливаем fв 1, а затем пропускаем остальные команды и переходим к nextстроке.

Для линий вне диапазона /3/,/5/переход не выполняется, и это 1приводит к печати строки. Более подробно, 1это условие. Поскольку 1это не ноль, условие оценивается как истинное. Поскольку никакое действие не связано с условием, выполняется действие по умолчанию, которое заключается в печати строки. Таким образом, 1это сокращение для печати строки.

Чтобы изменить файл на месте, эта -i inplaceопция может быть использована с GNU awk4.1 или выше:

awk -i inplace '/3/,/5/{if (!f)print "New Code"; f=1; next} 1' file
John1024
источник
прохладно. Я не очень хорош awk, не могли бы вы объяснить немного ваше awkвыражение лица
Рахул
1
@Rahul Конечно. Я добавил объяснение кода awk.
John1024
1
Спасибо Джон. Это именно то, что я искал.
Гиби
Намного проще удалить блок, а затем добавить новый в последнюю строку:sed '/3/,/4/d;/5/cNew Code' awk '/5/{print "New Code"}/3/,/5/{next}1'
Costas
1

Исходя из вышеизложенного, я придумаю решение, использующее ex

seq 15 > test1.txt
ex test1.txt << EOEX
/^7/,/^9/c
abcd
123
.xyz
hfr4
.
w!
q
EOEX
cat test1.txt

Выше дает

1
2
3
4
5
6
abcd
123
.xyz
hfr4
10
11
12
13
14
15

Спасибо, g-man, чтобы я знал о команде изменения и дал разъяснения по поводу точки. Оба sedи exимеют почти одинаковый синтаксис для команды изменения (также для команды удаления, команды добавления и т. Д.).

gibies
источник