http://qs1969.pair.com?node_id=1189251

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

I would expect that the following would print out all five input lines:

echo -e '55\n44\n33\n22\n11\n' | perl -n -e '@a = <>; END{ print @a; } '

Instead, the first line gets eaten. The first line always gets eaten regardless of how many numbers I send to perl.

What is the explanation for the behavior? What should be changed so that all numbers sent to perl end up in @a?

Replies are listed 'Best First'.
Re: perl -n seemingly eating a line of input
by shmem (Chancellor) on May 01, 2017 at 11:42 UTC

    This happens because at the time your loop code @a = <>; is run, there has already been an assignment to $_.

    perl -MO=Deparse -n -e '@a = <>; END{ print @a; } ' LINE: while (defined($_ = <ARGV>)) { @a = <ARGV>; sub END { print @a; } ; }

    This captures the first line also into @a:

    echo -e '55\n44\n33\n22\n11\n' | perl -n -e '@a = ($_,<>); END{ print +@a; } '
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      Thanks. I see the problem now, though don't see the way around it. Adding the parenthesis catches the first number, but also produces an extra line that is empty.

        ...but also produces an extra line that is empty.

        That is due to your trailing \n and has nothing to do with the parenthesized $_,<> - compare

        echo -e '55\n44\n33\n22\n11\n' | perl -n -e '@a = ($_,<>); END{ print +@a; } ' echo -e '55\n44\n33\n22\n11' | perl -n -e '@a = ($_,<>); END{ print @a +; } '

        - because echo -e will add a newline to its argument, so there are two of them, and thus an empty line. Use echo -en to suppress that:

        echo -en '55\n44\n33\n22\n11\n' | perl -n -e '@a = ($_,<>); END{ print + @a; } '
        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        Don't use -n, or change the way you process the lines:
        echo -e '55\n44\n33\n22\n11\n' | perl -n -e 'push @a, $_; END{ print @ +a; } '

        Explanation: -n makes perl loop through the input lines, and my code puts each line in turn onto the array. After all input is processed, I print out the array.

        If you want to do -e '@a=<>;' and get all the lines, simply don't use -n.
Re: perl -n seemingly eating a line of input
by ikegami (Patriarch) on May 01, 2017 at 15:47 UTC

    perl -n seemingly eating a line of input

    Well yeah, that's the point of -n. Specifically, -n wraps your code with

    LINE: while (<>) { ... }

    Fix (with -n):

    perl -ne'push @a, $_; END { print @a; }'

    Fix (without -n):

    perl -e'@a = <>; print @a;'
Re: perl -n seemingly eating a line of input
by Anonymous Monk on May 01, 2017 at 22:44 UTC
    TIMTOWTDI! (just move trailing newline to beginning of string) xD
    echo -e '\n55\n44\n33\n22\n11' | perl -ne'@a = <>; END{ print @a; }'