
Angenommen, ich habe diese Datei, die nichts enthält außer
a
b
c
b
a
Bei Verwendung tac --separator=a file
in BASH [auf einem Debian-basierten Linux] erhalte ich Folgendes:
# empty line
# empty line
b
c
b
aacommand@prompt # two a just before the prompt
Frage: Soweit ich verstanden habe, --separator=a
definiert , dass a
der Umbruch innerhalb der Zeichenfolge markiert wird, anstatt newline
.Ist das richtig?
Ich habe dies mit anderen Zeichenfolgen und viel mehr Eingaben versucht und am Ende ein ziemliches Durcheinander gehabt. Die anderen Optionen funktionieren alle ganz gut, nehme ich an: Wenn ich verwende, tac --before
bekomme ich zuerst etwa fünf und nicht eine leere Zeile, aber das ist ungefähr das, was dann passieren sollte, oder?
Antwort1
tac
ist leichter zu verstehen, wenn es hauptsächlich dafür gedacht ist, nämlich wenn das Trennzeichen ein Datensatzabschlusszeichen ist, d. h. wenn das Trennzeichen nach dem letzten Datensatz erscheint. Es druckt die Datensätze (einschließlich jedes Abschlusszeichens) in umgekehrter Reihenfolge.
$ echo -n fooabara | tac -s a; echo
rabafooa
Die Eingabe besteht aus drei Datensätzen ( foo
, b
und r
), jeweils gefolgt vom Trennzeichen a
; die Ausgabe besteht aus drei Datensätzen ( r
, b
und foo
), jeweils gefolgt vom Trennzeichen a
.
Wenn der letzte Datensatz nicht mit einem Datensatzabschlusszeichen endet, wird er trotzdem zuerst ohne Datensatztrennzeichen gedruckt.
$ echo -n fooabar | tac -s a; echo
rbafooa
Der letzte Datensatz r
wird mit dem vorletzten Datensatz b
ohne Trennzeichen dazwischen verkettet, da am Ende des letzten Datensatzes kein Trennzeichen stand.
Ihre Eingabe sieht aufgrund der Zeilenumbrüche etwas verwirrender aus. Sehen wir es uns mit Kommas anstelle von Zeilenumbrüchen an:
$ echo -n a,b,c,b,a, | tac -s a; echo
,,b,c,b,aa
Es gibt drei Eingabedatensätze: einen leeren (mit einem Terminator a
), einen umfangreichen ,,b,c,b,
(ebenfalls mit einem Terminator) und einen ,
am Ende nicht abgeschlossenen. Diese Datensätze (jeder mit seinem Terminator, mit Ausnahme des letzten Datensatzes, der keinen Terminator hat) werden in umgekehrter Reihenfolge gedruckt.
Ihre Verwirrung rührt wahrscheinlich daher, dass Sie bei „Separator“ von vornherein einen Separator erwarten – das ist jedoch eine falsche Bezeichnung: In Wirklichkeit handelt es sich dabei um einen Datensatzabschluss. --before
macht ihn stattdessen zu einem Initiator.
Antwort2
Das folgende Beispiel kann bei der Verwendung der --regex
Option hilfreich sein:
$ cat records
---1---
1
2
3
---2
A
B
C
---3--
a
b
c
$ tac --before --regex --separator=^---[0-9]+-*$ records
---3--
a
b
c
---2
A
B
C
---1---
1
2
3
In diesem Beispiel records
enthält die Datei mehrzeilige Datensätze, die jeweils mit einer Zeile ( ^...$
) beginnen, die mit beginnt ---
, gefolgt von einer Zahl ( [0-9]+
) und einer optionalen Folge von Minuszeichen ( -*
). Man kann sehen, dass die Zeilenreihenfolge in jedem Datensatz und seine Kopfzeile erhalten bleiben.
Ich verwende tac
diese Methode, um Einträge in Protokolldateien in umgekehrter Reihenfolge anzuzeigen, wie es in Feed-Anwendungen wie Twitter verwendet wird. Um beispielsweise nur die letzten beiden Datensätze in umgekehrter Reihenfolge auszudrucken:
tac --before --regex --separator=^---[0-9]+-*$ example \
| awk '/^---[0-9]+-*$/ {c++} c>2 {exit}{print}'