http://qs321.pair.com?node_id=1164417

elevenfly has asked for the wisdom of the Perl Monks concerning the following question:

Hello! I found a code like this:

 perl -n -e 'print $_ if 1..2' test.txt

This code will only print the first and second in test.txt and I was told that if will compare $. with the line number I provide. But what is the reason for that?

Can anyone provide any help?

Thanks!,

Replies are listed 'Best First'.
Re: How does $. work in one liner?
by AnomalousMonk (Archbishop) on May 28, 2016 at 22:41 UTC

      There's nothing special about one-liners, not even the options which can be present in the shebang. The -n option on the other hand can make using $. a little more tricky, as it will not be reset from one file to the other if you are processing several at once. You can force it to be reset by closing the file handle as shown in eof, but personally at this point I would consider turning the one-liner into a .pl file. The $. issue is still true in a file script when using <>, but I haven't often seen it used to read from files rather than STDIN outside of a one-liner.

        In fact Eily is precise as always elevenfly, and he pointed exactly where $. is special in oneliners.

        He gave you the definition, i'll add an example. Given a.txt and b.txt as following:

        #cat a.txt a file line 1 a file line 2 a file line 3 #cat b.txt b file line 1 b file line 2 b file line 3
        if you use $. to check line number (and $. is implicit for a bare .. flip-flop operator), you have:
        #perl -ne "print if 1..2" a.txt b.txt a file line 1 a file line 2
        and so is because $. does not reset automatically for an implicit close of the filehandle (and -n iterates across file given as arguments and reopen each time ARGV so without explicitly closing it).

        But if you use the right idiom close ARGV if eof everything runs as expected: $. is reset by the explicit close that happens only if eof is encounterd:

        #perl -ne "print if 1..2; close ARGV if eof" a.txt b.txt a file line 1 a file line 2 b file line 1 b file line 2

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Thank you! perlop really talks about that!

Re: How does $. work in one liner?
by Eily (Monsignor) on May 28, 2016 at 23:30 UTC

    ++AnomalousMonk for the link to the range operator. This is a good example of the perl philosphy of "Do what I mean" which really is "use context to understand what I really meant" as in perl many things work differently depending on context. The .. operator is often better understood in list context @array = 1..10; where it means "all the element from 1 to 10". The construct you have here keeps this "from", "to" meaning, except it makes no sense to generate a list of elements in a single test (scalar, or even more specifically boolean context). So the sense that has been chosen for this test to be true "from 1 to 2" is to compare $. with the values. 1..2 now means "from line 1 to line 2".

Re: How does $. work in one liner?
by eyepopslikeamosquito (Archbishop) on May 29, 2016 at 04:08 UTC
      In your example, you don't need the $_. This will print lines 1 and 2 from the file test.txt:

      Assuming an OS that follows the POSIX spirit, this will also print the first two lines of a file, but probably without reading the entire file, and probably without starting an interpreter:

      head -n 2 test.txt

      (POSIX: head)

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: How does $. work in one liner?
by stevieb (Canon) on May 28, 2016 at 22:32 UTC

    Welcome elevenfly to the Monastery!

    This is a great question. After a quick glance in perlrun, it doesn't state anything about the special line-number variable ($.).