Заменить блок текста внутри файла, используя содержимое другого файла, используя sed

#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}