So fügen Sie in Bash am Anfang jedes Absatzes Text ein

So fügen Sie in Bash am Anfang jedes Absatzes Text ein

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:

  1. Perl im „Absatzmodus“

    perl -00pe 's/^/$./' file 
    

    Erläuterung

    Das -00aktiviert den Absatzmodus, in dem „Zeilen“ durch aufeinanderfolgende \n\n, also Absätze, definiert werden. Das s/^/$./ersetzt den Zeilenanfang ( ^) durch die aktuelle „Zeilen“- (Absatz-)Nummer $.. Das weist Perl an, jede Zeile der Eingabedatei auszudrucken, nachdem das darin -pangegebene Skript ausgeführt wurde .-e

  2. 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 verwenden head:

    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.

verwandte Informationen