I understand that I can get the current line number of a file I am looping through with the builtin variable $.
. As an experiment, I used that to prefix each line in a file with the value of $.
(the current line number). However, this did not work as expected. I.e. given the following file contents
line one
line two
line three
then I would expect the following code to prefix each line with its line number
for my $line (<FILE>) {
print "$. : $line";
}
but, instead, it gives the following output
3 line one
3 line two
3 line three
prefixing each line with the number of lines in the file. Instead of the current line.
That's because the way you wrote the loop reads the entire file before looping over the lines. Unless you have a special reason to need something better than simple sequential access to the file, you should use
while
instead offor
, like this:When
<
filehandle>
is called in list context (as it is in yourfor
loop), it returns the entire contents of the file as a list of lines. Therefore, your code behaves in much the same way as if you had written this instead:To achieve your desired result, you should call
<>
repeatedly in scalar context (which the assignment in thewhile
condition does), to fetch one line at a time from the file and execute the body of the loop with$.
set to the correct number.Also, global filehandles are considered to be bad practice. For several reasons, it's better to use a filehandle referenced by a lexical variable instead, like this:
Also, since
$.
is a global variable containing the line number from the most recently executed read operation, you shouldn't rely on it if there's any chance of another read occurring between the<$file>
and theprint
. Instead, ask the filehandle you're using for its line number:Which even works, if somewhat more awkwardly, with a global filehandle:
... even the default one read by an empty
<>
, which is really namedARGV
: