I just realized that I could solve this problem by reversing line numbers from 1, 2, 3,...,n to n, n-1, ..., 3,2,1 and then use the same logic as earlier. So I want to know how can I reverse the order of lines?
4 Answers
tac
(cat
backwards, and included in coreutils
as well) will cat
a file in reverse order:
$ cat /tmp/test
One
Two
Three
$ tac /tmp/test
Three
Two
One
(In the case of the particular problem you mentioned the solutions there are better than reversing the entire file just so you can append a file and reverse the whole file again)

- 93,103
- 40
- 240
- 233
For your particular problem, this is not the most efficient way to go about it, however, you can use any of the following to print a file with lines in reverse order, with varying degrees of portability (tac
for example is not included by default on many Unixes):
sed '1!G;h;$!d' [file]
awk '{f[n=NR]=$0}END{for(i=n;i>0;i--)print f[i]}' [file]
perl -e 'print reverse<>' [file]
tac [file]
On my system the fastest is tac
, as tested by the following:
$ printf '%s\n' {a..z}{a..z}{a..z} > foo
$ time sed '1!G;h;$!d' foo > /dev/null 2>&1
real 0m0.582s
user 0m0.544s
sys 0m0.012s
$ time awk '{f[n=NR]=$0}END{for(i=n;i>0;i--)print f[i]}' foo > /dev/null 2>&1
real 0m0.060s
user 0m0.052s
sys 0m0.008s
$ time perl -e 'print reverse<>' foo > /dev/null 2>&1
real 0m0.021s
user 0m0.016s
sys 0m0.004s
$ time tac foo > /dev/null 2>&1
real 0m0.003s
user 0m0.004s
sys 0m0.000s
... so if you have tac
, use it, but otherwise, use perl
or awk
.

- 125,559
- 25
- 270
- 266
-
Your
awk
one-liner'sprintf
will fail if the input contains % sign. Better use a separate format string:printf "%s",i
. – manatwork Sep 19 '11 at 07:56 -
-
Taking another look at your code alternatives, those concatenations in
awk
andperl
are slowing down your solutions. I suggest to change your strategy and spare the concatenations by using arrays:awk '{f[n=NR]=$0}END{for(i=n;i>0;i--)print f[i]}' foo
andperl -ne 'push@f,$_;END{print reverse@f}' foo
. – manatwork Sep 19 '11 at 13:38 -
@manatwork - Thanks for the
awk
array suggestion, that was the original one I posted, but I forgot to compare the efficiency of the two methods. As for perl, is there any reason not to simply doperl -e 'print reverse<>'
? It seems to be slightly less expensive. – Chris Down Sep 19 '11 at 13:46 -
GNU utilities (Linux, Cygwin) and BusyBox have the tac
command, which reverses the order of the lines in a text file.
On systems that don't have tac
, you can work it from standard commands. Chris Down's answer shows a few ways to do it by storing the file entirely in memory. For a very large file, a way that will work without thrashing on most unices is to make sort
do the reversal. This is not as efficient for medium-sized files, but sort implementations can typically cope with files that are larger than the available memory.
nl | sort -nr | sed 's/.*\t//'
(Replace \t
by a literal tab character.)
As already noted by Michael Mrozek, reversing lines is a poor way of prepending data to a file. The method is hard to understand, and performs a lot of extra work.

- 829,060
-
sort -n
should besort -rn
to reverse the result of the comparisons. – Chris Down Sep 18 '11 at 18:02
\n
) marking the end of each line. There are a few OSes that store files as arrays of records (lines), but even if you were to access such files from unix, there is no API to read them other than byte by byte. – Gilles 'SO- stop being evil' Sep 18 '11 at 17:41