Die Option des Tac-Befehls erzeugt eine seltsame Ausgabe

Die Option des Tac-Befehls erzeugt eine seltsame Ausgabe

Angenommen, ich habe diese Datei, die nichts enthält außer

a
b
c
b
a

Bei Verwendung tac --separator=a filein 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=adefiniert , dass ader 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 --beforebekomme ich zuerst etwa fünf und nicht eine leere Zeile, aber das ist ungefähr das, was dann passieren sollte, oder?

Antwort1

tacist 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, bund r), jeweils gefolgt vom Trennzeichen a; die Ausgabe besteht aus drei Datensätzen ( r, bund 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 rwird mit dem vorletzten Datensatz bohne 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. --beforemacht ihn stattdessen zu einem Initiator.

Antwort2

Das folgende Beispiel kann bei der Verwendung der --regexOption 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 recordsenthä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 tacdiese 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}'

verwandte Informationen