Given a start and end line number, what's the fastest way to read a range of lines from a file into a variable?
views:
121answers:
5# cat x.pl
#!/usr/bin/perl
my @lines;
my $start = 2;
my $end = 4;
my $i = 0;
for( $i=0; $i<$start; $i++ )
{
scalar(<STDIN>);
}
for( ; $i<=$end; $i++ )
{
push @lines, scalar(<STDIN>);
}
print @lines;
# cat xxx
1
2
3
4
5
# cat xxx | ./x.pl
3
4
5
#
Otherwise, you're reading a lot of extra lines at the end you don't need to. As it is, the print @lines may be copying memory, so iterating the print while reading the second for-loop might be a better idea. But if you need to "store it" in a variable in perl, then you may not be able to get around it.
Update:
You could do it in one loop with a "continue if $. < $start" but you need to make sure to reset "$." manually on eof() if you're iterating over or <>.
The following will load all desired lines of a file into an array variable. It will stop reading the input file as soon as the end line number is reached:
use strict;
use warnings;
my $start = 3;
my $end = 6;
my @lines;
while (<>) {
last if $. > $end;
push @lines, $_ if $. >= $start;
}
Reading line by line isn't going to be optimal. Fortunately someone has done the hardwork already :) use Tie::File; it present the file as an array. http://perldoc.perl.org/Tie/File.html
You can use flip-flop operators
while(<>) {
if (($. == 3) .. ($. == 7)) {
push @result, $_;
}
Use the range operator .. (also known as the flip-flop operator), which offers the following syntactic sugar:
If either operand of scalar
..is a constant expression, that operand is considered true if it is equal (==) to the current input line number (the$.variable).
If you plan to do this for multiple files via <>, be sure to close the implicit ARGV filehandle as described in the perlfunc documentation for the eof operator. (This resets the line count in $..)
The program below collects in the variable $lines lines 3 through 5 of all files named on the command line and prints them at the end.
#! /usr/bin/perl
use warnings;
use strict;
my $lines;
while (<>) {
$lines .= $_ if 3 .. 5;
}
continue {
close ARGV if eof;
}
print $lines;
Sample run:
$ ./prog.pl prog.pl prog.c main.hs
use warnings;
use strict;
int main(void)
{
import Data.Function (on)
import Data.List (sortBy)
--import Data.Ord (comparing)