【问题标题】:Why output on perl eval differ between common bash output and redirection STDOUT + STDERR into file?为什么 perl eval 上的输出在普通 bash 输出和将 STDOUT + STDERR 重定向到文件之间有所不同?
【发布时间】:2015-04-13 23:41:50
【问题描述】:

我的代码是:

  perl -e'
  use strict; use warnings;

  my $a={};

  eval{ test(); };

  sub test{
     print "11\n";
     if( $a->{aa} eq "aa"){
        print "aa\n";
     }
     else{
        print "bb\n";
     }
  }'

终端上的输出是:

  11
  Use of uninitialized value in string eq at -e line 9.
  bb

如果我在文件中重定向,输出顺序不同。为什么?

  perl -e'
  ...
  ' > t.log 2>&1

猫 t.log:

  Use of uninitialized value in string eq at -e line 9.
  11
  bb

我的 perl 版本:

  This is perl 5, version 18, subversion 4 (v5.18.4) built for x86_64-linux-thread-multi
  (with 20 registered patches, see perl -V for more detail)

【问题讨论】:

  • 到 STDERR 的输出通常不被缓冲,而其他输出被缓冲。在用例之后添加$|++;,您的所有输出都将是无缓冲的,并且顺序将是您所期望的。

标签: bash perl


【解决方案1】:

一个更简单的问题演示:

$ perl -e'print("abc\n"); warn("def\n");'
abc
def

$ perl -e'print("abc\n"); warn("def\n");' 2>&1 | cat
def
abc

这是由于 STDOUT 和 STDERR 的缓冲方式不同造成的。

  • STDERR 未缓冲。
  • 如果 STDOUT 连接到终端,则在遇到换行符时,STDOUT 会刷新其缓冲区。
  • STDOUT 在缓冲区已满时刷新缓冲区。

$| = 1; 关闭 STDOUT 的缓冲[1]

$ perl -e'$| = 1; print("abc\n"); warn("def\n");' 2>&1 | cat
abc
def

  1. 实际上,当前selected 的句柄,即print 在未指定句柄时写入的句柄,默认为STDOUT。

【讨论】:

    【解决方案2】:

    这只是一个自动刷新问题没有评估问题。

    解决办法是:

    perl -e'
    use strict; 
    use warnings;
    
    $|++; # <== this autoflush print output
    
    my $a={};
    test();
    
    sub test{ 
       print "11\n";
       if( $a->{aa} eq "aa"){
          print "aa\n";
       }
       else{
          print "bb\n";
       }
    }' > t.log 2>&1
    

    在某些情况下在终端上是同样的问题:

    perl -e'print("abc");打印(标准错误“定义\n”);打印("ghi\n");'

    获得正确顺序的唯一保存方法是打开自动刷新!

    @dgw + ikegami ==> 谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-14
      • 1970-01-01
      • 1970-01-01
      • 2014-07-22
      • 1970-01-01
      • 1970-01-01
      • 2014-08-05
      • 1970-01-01
      相关资源
      最近更新 更多