12

-b, --before

The separator is attached to the beginning of the record that it precedes in the file.

And I can't understand the following output:

$ echo -e "Hello\nNew\nWorld\n!" > file
$ tac file
!
World
New
Hello
$ tac -b file


!
World
NewHello

Why there is no newline between New and Hello?

23

tac works with records and their separators, attached, by default after the corresponding record. This is somewhat counter-intuitive compared to other record-based tools (such as AWK) where separators are detached.

With -b, the records, with their newline attached, are as follows (in original order):

  • Hello
  • \nNew
  • \nWorld
  • \n!
  • \n

Output in reverse, this becomes

\n\n!\nWorld\nNewHello

which corresponds to the output you see.

Without -b, the records, with their newline attached, are as follows:

  • Hello\n
  • New\n
  • World\n
  • !\n

Output in reverse, this becomes

!\nWorld\nNew\nHello\n
5

That does look strange partly due tac works in somewhat counter-intuitive way as to me. Let's make use of clearly visible separators — commas.

What would I expect to see as the result of the following command:

% echo -ne 'A,B,C' | tac -s,

?

Well, I see it as there's A separated from B separated from C. Thus (I conclude) being printed in reverse, they should constitute C,B,A. Let's check. Alas, it prints differently instead:

% echo -ne 'A,B,C' | tac -s,
CB,A,

We can conclude tac sticks for original separators placement: A still has it afterwards, as well as B does, but C didn't have it and hence it's printed as is.

What happens if I run tac with -b this time?

% echo -ne 'A,B,C' | tac -bs,
,C,BA

Seemingly it works this way for -b: it's going through the input in backward direction till it finds a separator. As it's found it's printed:

,. Then it prints the text it skipped while searching:

C. Then the cycle repeats:

,B. As there're no separators left, just the remainder is printed:

A.

Why there is no newline between New and Hello?

According to the explanation I've given above New would be on a new line because it was prefixed with new-line, but since Hello wasn't — it'd be printed as is.

  • Regarding your first part, it helps to understand tac’s counter-intuitive behaviour if you consider that its initial goal was to reverse text files, which end with a \n. The configurable separator does suggest that it can reverse records separated by arbitrary characters, in which case you don’t expect the text to end with a separator, but it doesn’t work that way :-(. Your explanation of -b is a fairly accurate description of coreutils’ implementation of tac; note however that tac always searches backwards (even without -b). – Stephen Kitt Oct 22 at 9:30
  • Indeed tac is always tac, even w/o -b – poige Oct 22 at 9:39

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.