Ich habe eine Datei mit mehreren Absätzen, die durch Leerzeilen getrennt sind. Technisch gesehen sind das keine Absätze, sondern nur Textabschnitte, die durch Leerzeilen getrennt sind.
Ich möchte die Absätze sozusagen nummerieren, indem ich in die erste Zeile jeder Zeile nach einer Leerzeile eine Nummer einfüge. Wenn meine Datei also lautet:
Dies ist Text. Dies ist weiterer Text. Noch mehr Text! Dies ist der Text in Abschnitt zwei. Noch etwas Text. Sie verstehen, was ich meine ...
Ich möchte, dass es heißt:
1Dies ist Text das ist mehr Text Noch mehr Text! 2Dies ist der Text in Abschnitt zwei. Noch etwas Text. Sie verstehen, was ich meine ...
Antwort1
Versuchen Sie dies mit integrierten Bash-Befehlen:
#!/bin/bash
l=1 # paragraph counter
echo -n $l # print paragraph counter without new line
while read x; do # read current line from file, see last line
if [[ $x == "" ]]; then # empty line?
echo # print empty line
read x # read next line from file, see last line
((l++)) # increment paragraph counter
echo -n $l # print paragraph counter without new line
fi
echo "$x" # print current line
done < file
Antwort2
Im Allgemeinen ist die Verwendung der Shell zum Textparsing sehr langsam und umständlich. Hier sind einige andere Optionen:
Perl im „Absatzmodus“
perl -00pe 's/^/$./' file
Erläuterung
Das
-00
aktiviert den Absatzmodus, in dem „Zeilen“ durch aufeinanderfolgende\n\n
, also Absätze, definiert werden. Dass/^/$./
ersetzt den Zeilenanfang (^
) durch die aktuelle „Zeilen“- (Absatz-)Nummer$.
. Das weist Perl an, jede Zeile der Eingabedatei auszudrucken, nachdem das darin-p
angegebene Skript ausgeführt wurde .-e
Ohhhh
awk -vRS='\n\n' -vORS='\n\n' '{print NR$0}' file
Erläuterung
-vRS='\n\n'
setzt den Datensatztrenner von awk auf aufeinanderfolgende Zeilenumbruchzeichen. Wie der Absatzmodus von Perl behandelt es Absätze als „Zeilen“. Wir sagen ihm dann, dass es die aktuelle Zeilennummer (NR
) und die aktuelle „Zeile“ drucken soll$0
. Das-vORS=
setzt den Datensatztrenner der Ausgabe auf aufeinanderfolgende Zeilenumbrüche, sodass Absätze auch in der Ausgabe durch Leerzeilen getrennt sind. Beachten Sie, dass dadurch am Ende der Ausgabe zwei leere Zeilen hinzugefügt werden. Um dies zu vermeiden, können Sie Folgendes verwendenhead
:awk -v RS='\n\n' -vORS='\n\n' '{print NR$0}' file | head -n -2
Zum Vergleich hier die Zeiten, die die verschiedenen Lösungen auf meinem System benötigten, wenn sie auf einer 10 MB großen Testdatei ausgeführt wurden:
$ time a.sh > /dev/null ## a.sh is Cyrus's solution
real 0m1.419s
user 0m1.308s
sys 0m0.104s
$ time perl -00pe 's/^/$./' file > /dev/null
real 0m0.087s
user 0m0.084s
sys 0m0.000s
$ time awk -v RS='\n\n' -vORS='\n\n' '{print NR$0}' file | head -n -2 >/dev/null
real 0m0.074s
user 0m0.056s
sys 0m0.020s
Wie Sie oben sehen können, sind sowohl die Perl- als auch die AWK-Lösung um eine Größenordnung schneller als der Shell-Ansatz.