Sie können verschiedene Ansätze wählen, je nachdem, ob die awkBehandlung RSals einzelnes Zeichen (wie bei herkömmlichen awkImplementierungen) oder als regulärer Ausdruck (wie bei gawkoder mawk) erfolgt. Leere Dateien sind auch schwierig zu betrachten, da sie awkzum Überspringen neigen.
gawk, mawkOder andere , awkwo Implementierungen RSkann ein regulärer Ausdruck sein.
In diesen Implementierungen (zum Beispiel mawk: Beachten Sie, dass einige Betriebssysteme wie Debian eine sehr alte Version anstelle der von @ThomasDickey gepflegten modernen Version liefern ), RSist das Datensatztrennzeichen dieses Zeichen, wenn es ein einzelnes Zeichen enthält, oder wird awkin den Absatzmodus versetzt , wenn RSes leer ist. oder behandelt RSals regulären Ausdruck anders.
Die Lösung besteht darin, einen regulären Ausdruck zu verwenden, der möglicherweise nicht übereinstimmt. Manche kommen wie x^oder in den Sinn $x( xvor dem Start oder nach dem Ende). Einige (besonders mit gawk) sind jedoch teurer als andere. Bisher habe ich festgestellt, dass dies ^$das effizienteste ist. Es kann nur auf eine leere Eingabe passen, aber dann gäbe es nichts, gegen das man passen könnte.
Wir können also:
awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Eine Einschränkung ist jedoch, dass leere Dateien übersprungen werden (im Gegensatz zu perl -0777 -n). Dies kann mit GNU behoben awkwerden, indem der Code ENDFILEstattdessen in eine Anweisung geschrieben wird. Wir müssen aber auch $0in einer BEGINFILE-Anweisung zurücksetzen, da sie sonst nach der Verarbeitung einer leeren Datei nicht zurückgesetzt würde:
gawk -v RS='^$' '
BEGINFILE{$0 = ""}
ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
traditionelle awkImplementierungen, POSIXawk
In diesen Fällen RShandelt es sich nur um ein Zeichen, sie haben kein BEGINFILE/ ENDFILE, sie haben keine RTVariable, sie können das NUL-Zeichen auch im Allgemeinen nicht verarbeiten.
Sie würden denken, dass using RS='\0'dann funktionieren könnte, da sie ohnehin keine Eingaben verarbeiten können, die das NUL-Byte enthalten, aber nein, das wird RS='\0'in traditionellen Implementierungen als behandelt RS=, was der Absatzmodus ist.
Eine Lösung kann darin bestehen, ein Zeichen zu verwenden, das in der Eingabe nicht vorkommt \1. In Gebietsschemas für Mehrbytezeichen können Sie sogar Byte-Sequenzen erstellen, die sehr unwahrscheinlich sind, da sie nicht zugewiesene Zeichen oder Nicht-Zeichen wie $'\U10FFFE'in UTF-8-Gebietsschemas bilden. Nicht wirklich kinderleicht und Sie haben auch ein Problem mit leeren Dateien.
Eine andere Lösung kann darin bestehen, die gesamte Eingabe in einer Variablen zu speichern und diese am Ende in der END-Anweisung zu verarbeiten. Das heißt, Sie können jedoch immer nur eine Datei gleichzeitig verarbeiten:
awk '{content = content $0 RS}
END{$0 = content
printf "%s: <%s>\n", FILENAME, $0
}' file
Das ist das Äquivalent von sed's:
sed '
:1
$!{
N;b1
}
...' file1
Ein weiteres Problem bei diesem Ansatz ist, dass, wenn die Datei nicht mit einem Zeilenumbruchzeichen endete (und nicht leer war), $0am Ende noch eines willkürlich hinzugefügt wird (mit würden gawkSie das umgehen, indem Sie RTanstelle von RSin das verwenden Code oben). Ein Vorteil ist, dass Sie die Anzahl der Zeilen in der Datei in NR/ notieren FNR.