
Question:
Given a start and end line number, what's the fastest way to read a range of lines from a file into a variable?
Solution:1
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; }
Solution:2
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)
Solution:3
You can use flip-flop operators
while(<>) { if (($. == 3) .. ($. == 7)) { push @result, $_; }
Solution:4
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
Solution: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 <>.
Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
EmoticonEmoticon