【问题标题】:why does perl while (<>) fail to count or print the first line为什么 perl while (<>) 无法计算或打印第一行
【发布时间】:2020-04-07 18:31:37
【问题描述】:

我想计算文件中的行数并打印一个取决于行号的字符串。但是我的while 循环错过了第一行。我相信while (&lt;&gt;) 构造对于增加$n 变量是必要的;无论如何,这个结构在 perl 中不是很标准吗?

如何让while 循环打印第一行?还是我不应该使用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

【问题讨论】:

    标签: perl while-loop stdin


    【解决方案1】:

    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 "$.:$_"'
    

    最好的

    【讨论】:

    • 那么$. 变量呢? perlvar
    • perl -pe '$.: ' somefile 应该足够了(Windows:perl -pe "print \"$.: \"" 4k.m3u)
    • @Polar Bear,这不是有效的代码。你的意思是perl -pe'$_ = "$.:$_"' 但我会选择更具可读性的perl -ne'print "$.:$_"'
    • @北极熊我指的是第一个sn-p
    • @PolarBear perl -pe'$.: ' 怎么可能工作?这是一个语法错误。里面只有:
    【解决方案2】:

    有一种方法可以弄清楚你的单线实际上在做什么。 B::Deparse 模块可以向您展示 perl 如何解释您的源代码。它实际上来自 O(大写字母 O,而不是零)命名空间,您可以使用 -M (ikegami explains this on Perlmonks) 加载它:

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

    嘿,谷歌搜索模块链接显示I wrote about this for The Effective Perler。同样的例子。我想我不是那么原始。

    如果你不能改变命令行,可能是因为它在一个大脚本的中间或什么的,你可以在PERL5OPT中设置选项。然后这些选项仅在会话中持续。我讨厌更改原始脚本,因为似乎无论我多么小心,我都会搞砸一些事情(我的大脑告诉我多少次“嘿,笨蛋,你知道什么是 git 分支,所以你应该先使用它” ):

    $ export PERL5OPT='-MO=Deparse'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-17
      • 1970-01-01
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多