Perl script to reverse the order of lines.

Nick Holloway alfie at cs.warwick.ac.uk
Fri Feb 15 03:49:20 AEST 1991


The included script reversing the order of lines in a file.  Unlike
'rev' which reverses the characters in each line, 'reverse' will
reverse the order of the lines.  Think of it as reversal in the other
dimension!  The usage is "reverse [ file ... ]"

The script is for you to do with as you please, though I would
appreciate the credit remaining in the source.  I must admit that after
the original use, I haven't used it since, but you may find it
useful...  one day.

Here are some of the thinking behind it.  I wanted a filter to do this,
and I realised that I could use the 'ed' trick doing "g/^/m0" to
reverse a file, but this would mean 'cat'ting to a temp file,
reversing, and then 'cat'ting again.  This turned out very slow for
large files (and 'ed' had an extra temp file of it's own).

I could use 'perl', using the script "print reverse ( <> )", but this
would mean that the whole file is slurped into memory.  This could be a
problem for very large files.

My perl solution is a halfway point.  It limits the amount of data held
in core.  This can be set by changing "$maxbuf".  If the amount of data
read exceeds this, it is dumped to a temp file, and the process
continues.  For reversal of small files, it will be reasonably fast,
since it is all done in core, and for larger files, the temp file stops
the process becoming bloated.  I found it worked for me.

The limit "$maxbuf" is not absolute, since lines longer than "$maxbuf"
are not split.  If the length of lines is small compared to it, then it
will be fairly faithful to this value.  Something to watch out for, is
that if the last line is missing the newline, in the output file, it
gets glued to the next line.

	Over to you,
		Alfie
--
Nick Holloway |  `O O'  | alfie at cs.warwick.ac.uk, alfie at warwick.UUCP,
[aka `Alfie'] | // ^ \\ | ..!uunet!mcsun!ukc!warwick!alfie

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	reverse.pl
# This archive created: Wed Feb 13 17:58:54 1991
export PATH; PATH=/bin:$PATH
if test -f 'reverse.pl'
then
	echo shar: will not over-write existing file "'reverse.pl'"
else
cat << \SHAR_EOF > 'reverse.pl'
#!/usr/local/bin/perl

# Program : reverse
# Usage   : reverse [ file ... ]
#             print out lines in files given (or stdin if none) in the 
#             reverse order on the standard output
# Author  : Nick Holloway <alfie at cs.warwick.ac.uk>
# Date    : 11th January 1991
# Place   : Computer Science Dept, University of Warwick, Coventry, UK

# $maxbuf - maximum number of bytes to keep in core
# $tmpdir - directory to keep temp file in (overridden by env var TMPDIR)
# @buffer - array used to keep current set of input lines
# @tell   - array holding position and number of lines dumped to temp file

#-- configuration section
$maxbuf = 8 * 1024;	# maximum number of bytes to keep in core
$tmpdir = '/tmp';	# default temporary directory

#-- let battle commence...
$0 =~ s%.*/%%;		# basename $0

#-- create temp file, open for update and unlink to avoid need to clean up.
$tmp = ( $ENV { 'TMPDIR' } || $tmpdir ) . "/reverse.$$";
open ( TMP, "+>$tmp" ) 
    || die ( "$0: can't open \"$tmp\": $!\n" );
unlink ( $tmp )
    || die ( "$0: unlink of \"$tmp\" failed: $!\n" );

#-- read input, dumping reversed portions to temp file if necessary
while ( <> ) {
    $bufsiz += length;
    if ( $bufsiz >= $maxbuf ) {
	push ( @tell, tell ( TMP ), 0+ at buffer );
	print TMP reverse @buffer;	# reverse, and dump buffer to file
	@buffer = ();			# empty buffer
	$bufsiz = length;		# new buffer size
    }
    push ( @buffer, $_ );
}

#-- print in-core buffer.
print reverse @buffer;

#-- for each section dumped to file, print these out.
while ( @tell ) {
    $lns = pop ( @tell );
    $pos = pop ( @tell );
    seek ( TMP, $pos, 0 ) ||		# move to saved postion in file
	die ( "$0: can't seek in temp file: $!\n" );
    for ( 1 .. $lns ) {			# print lines dumped previously
	print ''.<TMP>;
    }
}
SHAR_EOF
chmod +x 'reverse.pl'
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Alt.sources mailing list