Як замінити частину текстового файлу між маркерами іншим текстовим файлом?


26

Скажіть, у мене є такий текстовий файл:

# custom content section
a
b

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

Я хотів би замінити частину між GENERATED CONTENTтегами вмістом іншого файлу.

Який найпростіший спосіб це зробити?

Відповіді:


36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file

Відмінно. sedможе зробити набагато більше, ніж просто s/.../...!
DevSolar

Гммм не працює для мене, чи слід ставити команду sed в один рядок?
lzap

3
r insert_fileКоманда повинна бути останньою річчю на своїй лінії. Зауважте, що після нього не допускаються ні пробіли, ні коментарі. Код був протестований з використанням GNU sedз --posixувімкненою опцією, і він працював як очікувалося, тому він повинен працювати з будь- яким сумісним позитором sed .
Пітер.O

1
Святий молі, це круто! Це відбувається в моєму словнику sed! Надзвичайно корисний і красиво простий. Дякую!
DanielSmedegaardBuus

2
Зауважте, що редагування на місці вимагає, щоб ви зафіксували вихід sed (наприклад output=$(sed -e "..." existing_file)), а потім виконали заміну в другому проході (наприклад 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

Хороша робота. Набагато простіше, ніж у мене. :)
Д-р Кітті

4

Попередження: Це, безумовно, не найпростіший спосіб зробити це. (EDIT: 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 Crap, ти маєш рацію. Решта працює, хоча. Я це виправлю.
Д-р Кітті

3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF

Використання heredoc та редактора рядків ed. Перший рядок всередині heredoc - це видалити рядок 'd' після '+' the '### BEGIN gENERATED ...', а рядок перед '-' '### END GENERATED ...' другий рядок це вставити FILE2 після рядка ### END GENERATED ... '
Jetchisel

вибачте, що я мав на увазі, щоб вставити FILE2 після рядка "### BEGIN GENERATED .."
Jetchisel

Полегшись мені, людям, це все-таки мій перший раз :-). Також я, можливо, використовував слово те саме, але в іншому рішенні використовується не гередок, а printf та труба. У будь-якому випадку вибачте, якщо я помилився :-)
Jetchisel

Дякую, дуже читабельно! Btw - замість r FILE2вас можна сказати r !commandчитати з іншого сценарію.
Кос
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.