#sed
#sed
Вопрос:
Я хочу заменить блок текста, который находится между маркерами, содержимым другого файла. Я наткнулся на это решение, но оно работает только с одной строкой
$ sed -n '/foo/{p;:a;N;/bar/!ba;s/.*n/REPLACEMENTn/};p' file
line 1
line 2
foo
REPLACEMENT
bar
line 6
line 7
Я пытаюсь заставить следующее работать, но это не так.
content=`cat file_content`
sed -n '/foo/{p;:a;N;/bar/!ba;s/.*n/${content}n/};p' file
вывод
line 1
line 2
foo
${content}
bar
line 6
line 7
Как я могу получить ${content} для отображения выходных данных файла?
Комментарии:
1. sed -n ‘/foo/{p;:a;N;/bar/!ba;s/.*n/'»$ {content}»‘n /};p’ файл sed: -e выражение # 1, символ 34: незавершенная команда `s’
2. Помимо строки в одинарных кавычках в оболочке, запрещающей любое расширение,
content
может содержать символsed
, который отбрасывает …/
запутал бы его здесь. Возможно , вы захотите проверитьr
команду для чтения и добавления содержимого файлаsed
.3. sh-4.2$ echo «${content}» тест1 1 3 4 45 5 454 45454 4545 454 46 454 4 64 6 6 46 646 46 466 4 6464 646 46 64 46 646453 3 3 3 3 66 66
4. Что, если
foo
и / илиbar
произошло дважды в файле? Должны ли мы заменить текст с первого foo на первый бар, или с первого foo на последний бар, или с последнего foo на первый бар после него или что-то еще? Что, если foo существует, а bar нет? Должны ли мы заменить от foo до конца файла? Что, еслиfoo
бы он существовал как часть какой-то другой строки, напримерmyfoobad
? Что, еслиfoo
иbar
существующие в той же строке, напримерfoo REPLACEME bar
? Что, если foo или bar содержат метасимволы регулярных выражений — следует ли их рассматривать как литеральные символы или нет? и т.д. и т.п… Вам нужно многое уточнить о ваших требованиях.
Ответ №1:
Так что, я думаю, это должен быть достаточно короткий способ сделать это, чтобы заменить текст между foo
bar
строками и содержимым файла file_content
:
sed -e '/^foo$/,/^bar$/{/^bar$/{x;r content_file
D};d}' file
Для диапазона строк, соответствующих ^foo$
и ^bar$
. Если строка совпадает ^bar$
, замените (пустое) пространство для хранения на пространство шаблонов, прочитайте и добавьте содержимое content_file
, затем удалите пространство шаблонов до первой новой строки и начните следующий цикл с напоминания о пространстве шаблонов. Для всех других строк в этом диапазоне… просто удалите строку (удалите пробел и перейдите к следующей строке ввода).
В противном случае к результату вашего вопроса… любая строка, заключенная в одинарные кавычки, воспринимается оболочкой буквально и без какого-либо расширения (также переменных). '${content}'
означает буквально ${content}
, и это также является частью переданного аргумента sed
, в то время как функция text ( "${content}"
) с двойными кавычками все равно будет видеть, как оболочка расширяет переменную до ее значения, прежде чем стать частью sed
аргументов. Поскольку это все равно может привести к сбою содержимого sed
, я бы выбрал r
метод для более общего / надежного.
РЕДАКТИРОВАТЬ: Редактировать, сохраняя начальную и конечную строки (поскольку я неправильно понял вопрос):
sed -e '/^foo$/,/^bar$/{/^foo$/{r content_file
p};/^bar$/!d}' file
На этот раз для диапазона между совпадающими ^foo$
и ^bar$
… для сопоставления строк ^foo$
мы r
извлекаем содержимое из content_file
добавления его в пространство шаблонов, а затем p
удаляем его (из d
-за elete, которые следуют). Затем для всех строк в диапазоне, не соответствующих шаблону закрывающей строки ^bar$
, он просто отбрасывает его и движется дальше.
Комментарии:
1. это работает, как и ожидалось; но можете ли вы изменить ответ, чтобы сохранить foo и bar в файле.
Ответ №2:
Это может сработать для вас (GNU sed):
sed '/foo/!b;:a;$b;N;/bar/!ba;P;s/.*n//;e cat contentFile' file
Выведите все строки до одной, содержащей foo
.
Если это последняя строка, то никогда не будет строки, содержащей bar
so break out и не вставляйте contentFile
.
В противном случае добавьте следующую строку и проверьте, содержит bar
ли она, если не повторяется.
Теперь пространство шаблонов должно содержать оба foo
и bar
так, выведите первую строку (содержащую foo
), удалите все другие строки, кроме содержащей bar
, распечатайте файл contentFile
, а затем распечатайте последнюю строку содержащей коллекции bar
.
Примечание. При этом не вставляется contentFile
, если оба foo
и bar
не существуют file
. Также e
команда немедленно оценит cat contentFile
и вставит результат в выходной поток перед печатью строки, содержащей bar
, тогда r
как команда всегда печатает в выходной поток после неявной печати цикла sed. Альтернативный:
sed -ne '/foo/{p;:a;n;/bar/!ba;e cat contentFile' -e '};p' file
Однако это решение будет печатать только строки перед foo
, если file
не содержит строки bar
.
Ответ №3:
sed '/foo/,/bar/{//!d;/foo/s//amp;n'${content}'/}' file
Из foo в bar удалите строки, не соответствующие предыдущему совпадению //!d
.
В строке foo замените match amp;
на match, за которым следует n${content}