6

I want to use the tacto reverse a text file character by character. On the info page for coreutils I found an example saying: #Reverse a file character by character tac -r -s 'x\|[^x]'

However running tac -r -s seems to open standard input instead of printing the file. What does 'x\|[^x]' mean and what should I be doing?

I also noted that the output for tac [file] and tac -r [file] are same and they're the same as cat [file]. Still can't figure out char by char reverse.

3
  • So did you try the command it told you to or not? May 28, 2018 at 6:35
  • 1
    Are you talking about reversing the order of the lines and then reversing the order of the characters of the lines as well? Do you have rev?
    – Kusalananda
    May 28, 2018 at 6:39
  • Reversing characters not lines.
    – Weezy
    May 28, 2018 at 8:57

2 Answers 2

11

To reverse a file character-by-character using tac, use:

tac -r -s 'x\|[^x]'

This is documented in info tac:

# Reverse a file character by character.
tac -r -s 'x\|[^x]'

-r causes the separator to be treated as a regular expression. -s SEP uses SEP as the separator. x\|[^x] is a regular expression that matches every character (those that are x, and those that are not x).

$ cat testfile
abc
def
ghi
$ tac -r -s 'x\|[^x]' testfile

ihg
fed
cba%
$

tac file is not the same as cat file unless file has only one line. tac -r file is the same as tac file because the default separator is \n, which is the same when treated as a regular expression and not.

2
  • 1
    Wouldn't . work just as well as the regex? What does this match that . doesn't? \n?
    – muru
    May 28, 2018 at 9:06
  • 2
    @muru Yes, if you use . it swaps bytes over the \n: printf 'ab\ncd\n'|tac -r -s . |hexdump -c -> \n d \n c b a, and tac -r -s . | tac -r -s . isn't idempotent. May 28, 2018 at 9:13
4

If you're not concerned about the LF character (see mosvy's comments), then it is much more efficient to use rev rather than tac -r -s 'x\|[^x]', piping it to tac if needed.

$ cat testfile
abc
def
ghi
$ rev testfile
cba
fed
ihg
$ rev testfile|tac
ihg
fed
cba

This solution is way cheaper than tac -r -s 'x\|[^x]' because regular expressions tend to slow things down quite dramatically.

3
  • 1
    Indeed. A ~tenfold speedup. But it's not actually reversing the input character by character: in printf "foo\nbar\n" | rev | tac, the output will not start with "\n" and end with "f", but start with "r" and end with "\n" ;-)
    – mosvy
    Dec 13, 2019 at 21:22
  • 1
    you can replace the rev with perl -ne 'print scalar reverse', though.
    – mosvy
    Dec 13, 2019 at 21:31
  • @mosvy Thanks for the hint, added a warning. ;) Dec 13, 2019 at 21:43

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.