Как заменить часть текстового файла между маркерами другим текстовым файлом?

26

Скажем, у меня есть текстовый файл, как это:

# custom content section
a
b

### BEGIN GENERATED CONTENT
c
d
### END GENERATED CONTENT

Я хотел бы заменить часть между GENERATED CONTENTтегами содержимым другого файла.

Какой самый простой способ сделать это?

smokris
источник

Ответы:

36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file
Peter.O
источник
Превосходно. sedможет сделать гораздо больше, чем просто s/.../...!
DevSolar
Хммм не работает для меня, я должен поставить команду Sed в одну строку?
августа
3
Команда r insert_fileдолжна быть последней на ее линии. Обратите внимание, что ни пробел, ни комментарии после него не допускаются. Код был протестирован с использованием GNU sedс --posixвключенной опцией, и он работал как положено, поэтому он должен работать с любым posix-совместимым sed .
Peter.O
1
Боже мой, это круто! Это происходит в моем словаре sed! Великолепно полезно и красиво просто. Спасибо!
DanielSmedegaardBuus
2
Обратите внимание, что редактирование на месте требует, чтобы вы output=$(sed -e "..." existing_file)перехватили выходные данные sed (например, ), а затем выполнили замену во втором проходе (например echo "$output" > existing_file), поскольку попытка перенаправления в файл, из которого вы читаете, приведет к его усечению до чтения содержимого.
Крис Тонкинсон
5
newContent=`cat new_file`
perl -0777 -i -pe "s/(### BEGIN GENERATED CONTENT\\n).*(\\n### END GENERATED CONTENT)/\$1$newContent\$2/s" existing_file
smokris
источник
Хорошая работа. Гораздо проще, чем у меня. :)
Доктор Китти
4

Предупреждение: это определенно не самый простой способ сделать это. (РЕДАКТИРОВАТЬ: bash работает; POSIX grep тоже хорошо)

Если основной текст находится в файле «main», а сгенерированный контент - в файле «gen», вы можете сделать следующее:

#!/bin/bash
BEGIN_GEN=$(cat main | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
END_GEN=$(cat main | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
cat <(head -n $(expr $BEGIN_GEN - 1) main) gen <(tail -n +$(expr $END_GEN + 1) main) >temp
mv temp main
Доктор Китти
источник
Это работает? Я думаю, что ваша последняя строка откроется mainдля записи, очистки, прежде чем она будет прочитана кошкой.
Чепнер
@chepner Дерьмо, ты прав. Остальное работает, хотя. Я исправлю это.
Доктор Китти
3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF
Jetchisel
источник
Использование heredoc и редактора ed line. Первая строка внутри heredoc должна удалить 'd' строку после '+' '### BEGIN gENERATED ...' и строку перед '-' '### END GENERATED ...' во второй строке это вставить FILE2 после строки ### END GENERATED ... '
Jetchisel
извините, что я имел в виду, вставьте FILE2 после строки "### BEGIN GENERATED .."
Jetchisel
Полегче на меня, ребята, это ведь мой первый раз :-). Также я мог бы использовать слово то же самое, но другое решение использует не heredocs, а printf и pipe. В любом случае извиняюсь, если я допустил ошибку :-)
Jetchisel
Спасибо, очень читабельно! Кстати - вместо r FILE2вас можно сказать r !commandчитать из другого скрипта.
Кос