4

Say I have this file, containing nothing but

a
b
c
b
a

Using tac --separator=a file in BASH [on a Debian based Linux], I get this:

                  # empty line
                  # empty line
b
c
b
aacommand@prompt  # two a just before the prompt


Question: As far as I understood, --separator=a defines that a marks the break inside the string, instead of newline. Is this right?

I have tried this with other strings an much more input and ended up with quite a mess. The other options all work quite right, I presume: If I use tac --before I first get about five than one empty lines, but then this is about what should happen, right?

9

tac is easier to understand in the case it's primarily designed for, which is when the separator is a record terminator, i.e. the separator appears after the last record. It prints the records (including each terminator) in reverse order.

$ echo -n fooabara | tac -s a; echo
rabafooa

The input consists of three records (foo, b and r), each followed by the separator a; the output consists of three records (r, b and foo), each followed by the separator a.

If the last record doesn't end with a record terminator, it's still printed first, with no record separator.

$ echo -n fooabar | tac -s a; echo
rbafooa

The last record r ends up concatenated with the next-to-last record b with no separator in between, since there was no separator at the end of the last record.

Your input looks a bit more confusing because of the newlines. Let's see it with commas instead of newlines:

$ echo -n a,b,c,b,a, | tac -s a; echo
,,b,c,b,aa

There are three input records: an empty one (with a terminator a), the bulky one ,,b,c,b, (again with a terminator), and an unterminated , at the end. These records (each with their terminator, except for the last record which doesn't have a terminator) are printed in reverse order.

Your confusion probably comes from expecting the “separator” to be a separator — but that's a misnomer: it's really a record terminator. --before makes it an initiator instead.

  • Incredible answer, @Gilles, thank you very much! I really wonder where you get your information from, as I spent quite some time looking and found nothing close to what you provide here. Thank you so very much for your effort! – erch Apr 25 '13 at 20:52
1

The following example might help to use the --regex option:

$ 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 this example the file records contains multiline records, each started with a line (^...$) that starts with ---, followed by a number ([0-9]+) and an optional sequence of minus signs (-*). One can see the order of lines in each record and its header line are preserved.

I use trac this way to show log files entries in reverse order, as used in feed applications such as twitter. For instance to print only the last two records in reversed order:

tac --before --regex --separator=^---[0-9]+-*$ example \
 | awk '/^---[0-9]+-*$/ {c++} c>2 {exit}{print}'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.