Vijay
Vijay

Reputation: 67231

Line number of a file in Perl when multiple files are passed as arguments to perl cli

In awk if I give more than one file as an argument to awk, there are two special variables:

NR=line number corresponding to all the lines in all the files.

FNR=line number of the current file.

I know that in Perl, $. corresponds to NR (current line among lines in all of the files).

Is there anything comparable to FNR of AWK in Perl too?

Let's say I have some command line:

perl -pe 'print filename,<something special which hold the current file's line number>'  *.txt

This should give me output like:

file1.txt 1
file1.txt 2
file2.txt 1

Upvotes: 9

Views: 8740

Answers (3)

zzxyz
zzxyz

Reputation: 2981

I find this situation to be a very large drawback to using Perl. While this answer is suboptimal, performance-wise, and only fits situations involving xargs, I've typically found it the workaround I use 95% of the time. So the problem scenario:

git ls-files -z | xargs -0 perl -ne 'print "$ARGV:$.\t$_" if /#define oom/'

file.h:85806    #define oom() exit(-1)

That line number is obviously not correct, and you'll obviously get the same behavior with find Of course, with this regex, or other simpler Perl regexes, I'd just use awk or git grep -P. However, if you're dealing with a fairly complicated regular expression, or need other Perl features, that won't work...and the correct answers to this question further complicate what is already likely to be a complicated Perl one-liner.

So I just use the following:

git ls-files -z | xargs -0 -n1 perl -ne 'print "$ARGV:$.\t$_" if /#define oom/'

file.h:43       #define oom() exit(-1)

The -n1 xargs argument causes xargs to kick off a Perl process for each file, which results in the correct line numbers. You're looking at very significant performance impact, but I've found it acceptable for very large projects with millions of lines of code vs. solving it in Perl, which I find almost always requires an actual script vs. a one-liner. It is not acceptable for system-wide searches in the vast majority of cases.

Upvotes: 0

Zaid
Zaid

Reputation: 37146

Actually, the eof documentation shows a way to do this:

# reset line numbering on each input file
while (<>) {
    next if /^\s*#/;  # skip comments
    print "$.\t$_";
} continue {
    close ARGV if eof;  # Not eof()!
}

An example one-liner that prints the first line of all files:

$ perl -ne 'print "$ARGV : $_" if $. == 1; } continue { close ARGV if eof;' *txt

Upvotes: 6

choroba
choroba

Reputation: 241898

There is no such variable in Perl. But you should study eof to be able to write something like

perl -ne 'print join ":", $. + $sum, $., "\n"; $sum += $., $.=0  if eof;' *txt

Upvotes: 5

Related Questions