Wie ersetze ich einen Teil einer Textdatei zwischen Markierungen durch eine andere Textdatei?

26

Angenommen, ich habe eine Textdatei wie diese:

# custom content section
a
b

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

Ich möchte den Teil zwischen den GENERATED CONTENTTags durch den Inhalt einer anderen Datei ersetzen .

Was ist der einfachste Weg, dies zu tun?

Smokris
quelle

Antworten:

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
quelle
Ausgezeichnet. sedkann so viel mehr als nur s/.../...!
DevSolar
Hmmm funktioniert bei mir nicht, soll ich den sed-Befehl in eine Zeile setzen?
lzap
3
Der r insert_fileBefehl muss das Letzte in seiner Zeile sein. Beachten Sie, dass danach weder Leerzeichen noch Kommentare zulässig sind. Der Code wurde unter Verwendung von GNU sedmit --posixaktivierter Option getestet und funktionierte wie erwartet, daher sollte er mit allen posix-kompatiblen funktionieren sed .
Peter.O
1
Heilige Moly, das ist cool! Das geht in mein sed Wörterbuch! Hervorragend nützlich und wunderschön einfach. Vielen Dank!
DanielSmedegaardBuus
2
Beachten Sie, dass Sie für eine direkte Bearbeitung die Ausgabe von sed (z. B. output=$(sed -e "..." existing_file)) erfassen und dann in einem zweiten Durchgang (z. B. echo "$output" > existing_file) ersetzen müssen, da die Umleitung in eine Datei, aus der Sie lesen, dazu führt, dass sie abgeschnitten wird, bevor der Inhalt gelesen wird.
Chris Tonkinson
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
quelle
Gute Arbeit. Viel einfacher als meins. :)
Dr Kitty
4

Warnung: Dies ist definitiv nicht der einfachste Weg, dies zu tun. (EDIT: bash funktioniert; POSIX grep ist auch in Ordnung)

Wenn sich der Haupttext in der Datei "main" befindet und sich der generierte Inhalt in der Datei "gen" befindet, können Sie Folgendes tun:

#!/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
Dr. Kitty
quelle
Funktioniert das? Ich denke, Ihre letzte Zeile wird mainzum Schreiben geöffnet und gelöscht, bevor sie von cat gelesen wird.
Chepner
@chepner Mist, du hast recht. Der Rest funktioniert jedoch. Ich werde es reparieren.
Dr. Kitty
3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF
Jetchisel
quelle
Mit einem Heredoc und dem ed-Zeileneditor. Die erste Zeile innerhalb des Heredocs besteht darin, 'd' die Zeile nach '+' dem '### BEGIN gENERATED ...' und die Zeile vor '-' dem '### END GENERATED ...' der zweiten Zeile zu löschen soll FILE2 nach der Zeile ### END GENERATED ... '
einfügen
Entschuldigung, was ich meinte, war das Einfügen von FILE2 nach der Zeile '### BEGIN GENERATED ..'
Jetchisel
Lass es mich ruhig angehen, es ist immerhin mein erstes Mal :-). Ich hätte auch das gleiche Wort verwenden können, aber die andere Lösung verwendet keine Heredocs, sondern ein printf und eine Pipe. Auf jeden Fall entschuldige ich mich, wenn ich einen Fehler gemacht habe :-)
Jetchisel
Danke, sehr gut lesbar! Übrigens - statt r FILE2Sie können sagen r !command, aus einem anderen Skript zu lesen.
Kos,