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)