Tac command’s option creates strange output [comprehension question]

coreutilstext processingUtilities

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?

Best Answer

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.

Related Question