почему perl while (<>) не может сосчитать или напечатать первую строку - PullRequest
0 голосов
/ 07 апреля 2020

Я хочу посчитать строки в файле и вывести строку, которая зависит от номера строки. Но мой while l oop пропускает первую строчку. Я считаю, что конструкция while (<>) необходима для увеличения переменной $n; в любом случае, разве эта конструкция не является достаточно стандартной в perl?

Как мне получить while l oop для печати первой строки? Или я не должен использовать while?

> printf '%s\n%s\n' dog cat
dog
cat
> printf '%s\n%s\n' dog cat | perl -n -e 'use strict; use warnings; print; '
dog
cat
> printf '%s\n%s\n' dog cat | perl -n -e 'use strict; use warnings; while (<>) { print; } ' 
cat
> 
> printf '%s\n%s\n' dog cat | perl -n -e 'use strict; use warnings; my $n=0; while (<>) { $n++; print "$n:"; print; } ' 
1:cat

Ответы [ 2 ]

4 голосов
/ 07 апреля 2020

man perlrun показывает:

   -n   causes Perl to assume the following loop around your program, which makes it iterate over filename
        arguments somewhat like sed -n or awk:

          LINE:
            while (<>) {
                ...             # your program goes here
            }

        Note that the lines are not printed by default.  See "-p" to have lines printed.  If a file named by an
        argument cannot be opened for some reason, Perl warns you about it and moves on to the next file.

        Also note that "<>" passes command line arguments to "open" in perlfunc, which doesn't necessarily
        interpret them as file names.  See  perlop for possible security implications.
 ...
 ...     

      "BEGIN" and "END" blocks may be used to capture control before or after the implicit program loop, just as in awk.

Итак, на самом деле вы запускаете этот скрипт

LINE:
    while (<>) {
        # your progrem start
        use strict;
        use warnings;
        my $n=0;
        while (<>) {
            $n++;
            print "$n:";
            print;
        }
        # end
    }

Решение, просто удалите -n.

printf '%s\n%s\n' dog cat | perl -e 'use strict; use warnings; my $n=0; while (<>) { $n++; print "$n:"; print; }'

Напечатает:

1:dog
2:cat

или

printf '%s\n%s\n' dog cat | perl -ne 'print ++$n, ":$_"'

с тем же результатом

или

printf '%s\n%s\n' dog cat | perl -pe '++$n;s/^/$n:/'

но решение икегами

printf "one\ntwo\n" | perl -ne 'print "$.:$_"'

является ЛУЧШИМ

1 голос
/ 08 апреля 2020

Есть способ выяснить, что на самом деле делает ваш однострочник. Модуль B :: Deparse может показать вам, как perl интерпретировал ваш исходный код. Это на самом деле из пространства имен O (заглавная буква O, а не ноль), которое вы можете загрузить с помощью -M ( ikegami объясняет это на Perlmonks ):

$ perl -MO=Deparse -ne 'while(<>){print}' foo bar
LINE: while (defined($_ = readline ARGV)) {
    while (defined($_ = readline ARGV)) {
        print $_;
    }
-e syntax OK

Хех, поиск в Google для ссылка на модуль показывает Я писал об этом для The Effective Perler . Тот же пример. Полагаю, я не настолько оригинален.

Если вы не можете изменить командную строку, возможно, потому что она находится в середине большого скрипта или чего-то еще, вы можете установить опции в PERL5OPT. Затем эти параметры длятся только сеанс. Я ненавижу менять оригинальные сценарии, потому что кажется, что независимо от того, насколько я осторожен, я что-то напутал (сколько раз мой мозг говорил мне: «Эй, тупица, ты знаешь, что такое ветка git, так что ты должен был использовать это» первая "):

$ export PERL5OPT='-MO=Deparse'
...